原题链接:279. 完全平方数
解题思路:
- 本题类似于322. 零钱兑换,如果你对
322. 零钱兑换
不熟悉,可以先看题解。二者的区别是硬币种类不固定,在本题中,对于当前金额i
,硬币种类为小于i
的完全平方数。 - 该题递推的是从
1
开始,使用小于i
完全平方数,计算能够凑到i
的最小数量,由此不断累加到n
的过程。 - 创建一个长度为
n + 1
的dp
数组,用索引就表示从0
到n
的数字。 - 对于当前数字
i
,我们可以用for (let j = 1; j * j <= i; j++) {}
,计算出小于i
的完全平方数。 i
是由i - j * j
用1个j * j
凑过来,同时要保证它是所有结果中最小的一个,因此状态转移返程为:dp[i] = Math.min(dp[i], dp[i - j * j] + 1);
。
/**
* @param {number} n
* @return {number}
*/
var numSquares = function (n) {
// 需要计算到n,因此需要从0开始递推到n
// 由于要计算的是最小值,因此初始化为Infinity,避免计算错误
let dp = new Array(n + 1).fill(Infinity);
dp[0] = 0; // 0对应的可组合数字为0
// 从1开始才会有组合个数,一直递推到n
for (let i = 1; i < dp.length; i++) {
// 每次计算可用的完全平方数
// 判断可用的方法是j*j不超过当前数量i
for (let j = 1; j * j <= i; j++) {
// 因为j * j <= i,所以i - j * j不可能小于0,无需判断
dp[i] = Math.min(
dp[i], // 当前已储存了之前完全平方数的组合数量
// 当前的完全平方数数量,可由i - j * j加一个j * j而来
// 因此等于dp[i - j * j]的数量加1个j * j
dp[i - j * j] + 1,
);
}
}
// 递推到n时,就计算出了所有可能的数量
return dp[n];
};