给你一个整数
n,返回 和为n的完全平方数的最少数量 。完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,
1、4、9和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)