题目
给你一个整数
n
,返回 和为n
的完全平方数的最少数量 。完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,
1
、4
、9
和16
都是完全平方数,而3
和11
不是。
示例 1:
输入:n = 12
输出:3
解释:12 = 4 + 4 + 4
示例 2:
输入:n = 13
输出:2
解释:13 = 4 + 9
解答
算法思路
-
定义状态:
dp[i]
表示组成数字i所需的最少完全平方数个数 -
初始条件:
-
dp[0] = 0
(组成0需要0个数) -
其他位置初始化为
Infinity
(表示暂时无法组成)
-
-
状态转移:
-
遍历所有可能的完全平方数
i*i
(i从1开始,i*i<=n) -
对于每个完全平方数,更新它能影响到的所有数字j(从i*i到n,因为只有当目标金额
j
≥i*i
时,这个平方数才有可能被使用) -
dp[j] = min(dp[j], dp[j-i*i]+1)
含义:比较不适用当前平方和的个数(dp[j]
),和使用当前平方和后的个数(即dp[j-i*i]+1
)
-
-
最终结果:
dp[n]
算法执行过程示例
以n=12为例:
初始化
dp = [0, ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞]
i=1 (1²=1)
更新j=1到12:
dp = [0,1,2,3,4,5,6,7,8,9,10,11,12]
i=2 (2²=4)
更新j=4到12:
dp[4] = min(4, dp[0]+1) = 1 dp[5] = min(5, dp[1]+1) = 2 dp[6] = min(6, dp[2]+1) = 3 dp[7] = min(7, dp[3]+1) = 4 dp[8] = min(8, dp[4]+1) = 2 dp[9] = min(9, dp[5]+1) = 3 dp[10] = min(10, dp[6]+1) = 4 dp[11] = min(11, dp[7]+1) = 5 dp[12] = min(12, dp[8]+1) = 3
i=3 (3²=9)
更新j=9到12:
dp[9] = min(3, dp[0]+1) = 1 dp[10] = min(4, dp[1]+1) = 2 dp[11] = min(5, dp[2]+1) = 3 dp[12] = min(3, dp[3]+1) = 3
最终结果:dp[12] = 3
(4+4+4)
var numSquares = function (n) {
// 初始化dp数组,全部设为Infinity(不可达)
const dp = new Array(n + 1).fill(Infinity);
// 基础情况:组成0需要0个平方数
dp[0] = 0;
// 遍历所有可能的平方数基数i(i² <= n)
for (let i = 1; i * i <= n; i++) {
// 更新所有能被当前平方数影响的数字j
for (let j = i * i; j <= n; j++) {
// 状态转移:比较不使用当前平方数和使用的情况
dp[j] = Math.min(dp[j], dp[j - i * i] + 1);
}
}
return dp[n]; // 返回结果
};