知识点

记忆化搜索

思路

定义状态 f[i]为总和为i的最优分解, 由于可以全分解为1, 所以任何数都是存在合法分解的

我们可以根据当前选取什么数t 1 \leq t \leq \lfloor \sqrt{x} \rfloor , 将该问题转化为一个子问题

递归终点为x为0时 返回空数组

状态数为n, 每一次转移需要枚举\sqrt{n}次, 总的时间复杂度为 O(n\sqrt{n})

AC Code (C++)

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param n int整型 
     * @return int整型vector
     */
    const int INF = 0x3f3f3f3f;
    vector<int> numSquares(int n) {
        vector<vector<int>> f(n + 1);

        function<void(int)> dfs = [&](int x) {
            if (x == 0 or !f[x].empty()) return;
            int mn = INF, t = 0;
            for (int i = (int)sqrt(x); i; i --) {
                dfs(x - i * i);
                if (mn > f[x - i * i].size()) {
                    mn = f[x - i * i].size();
                    t = i;
                }
            }
            f[x] = f[x - t * t];
            f[x].push_back(t * t);
        };
        dfs(n);
        sort(f[n].begin(), f[n].end());
        return f[n];
    }
};