84.完全平方数

68 阅读1分钟

题目链接

给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。

完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,149 和 16 都是完全平方数,而 3 和 11 不是。

解法1 记忆化递归

思路

题目问最少需要几个完全平方数相加才能得到 n ,可以从 1 开始枚举,我们枚举所有小于 remain 的 完全平方数。递归时,我们把 remain 减去当前的完全平方数当做递归参数传递,看看能不能从 remain 中一步一步减完。

尝试了所有可能的平方数作为“第一步”,把这些方案的结果都拿出来,选出最小值。min 就是当前 remain 的最优解,即用最少的平方数组合成 remain

代码

function numSquares(n: number): number {
    const memo = new Map();

    const dfs = (remain) => {
        if (remain === 0) return 0;
        if (memo.has(remain)) return memo.get(remain);

        let min = Infinity;
        for (let i = 1; i * i <= remain; i++) {
            min = Math.min(min, dfs(remain - i * i) + 1);
        }
        memo.set(remain, min);
        return min;
    };

    return dfs(n);
};

时空复杂度

时间复杂度:O(n * sqrt(n))

空间复杂度:O(n)

解法2 动态规划

思路

把上面记忆化递归的思路稍加改变就可以推导出递归公式,而 dp 数组表示的就是 dp[i] 能够由完全平方数组成的最少个数。

代码

function numSquares(n: number): number {
    const dp = new Array(n + 1).fill(Infinity);
    dp[0] = 0;
    
    for (let i = 1; i <= n; i++) {
        for (let j = 1; j * j <= i; j++) {
            dp[i] = Math.min(dp[i], dp[i - j * j] + 1);
        }
    }

    return dp[n];
};

时空复杂度

时间复杂度:O(n * sqrt(n))

空间复杂度:O(n)