279_完全平方数[MEDIUM]
约 511 字大约 2 分钟
2026-03-19
给你一个整数 n ,返回和为 n 的完全平方数的最少数量。
完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。
例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。
示例 1:
输入:n = 12
输出:3
解释:12 = 4 + 4 + 4示例 2:
输入:n = 13
输出:2
解释:13 = 4 + 9解题思路
在数学上,一个数 n = n - m + m , m 可以写成 j*j,于是有 n = n - j*j + j+j
- 定义状态:
dp[i]是和为i的完全平方数最少数量 - 最坏情况:
n=1+1+1+...,所以最坏情况是dp[i] = n - 思路:需要两层循环,第一层遍历
i直到到达n, 第二层是找第一层i所有可能的完全平方数j*j - 转移方程:
dp[i]= 在所有可能的完全平方数中(j*j < i):- 要么选择上一个状态
dp[i-j*j]最小的 ,再加上一个j*j这 1 个数字, 也就是dp[i-j*j] + 1 - 要么不选择就是
dp[i]
- 要么选择上一个状态
或者这样理解:如果这个环节选择了 j*j 这个数,那为了凑齐和为 i ,剩下的数字是 i-j*j ,所以只要求 dp[i-j*j] 再加上这一环节的这个数,就得到 dp[i] 的解了
Java 实现
public int numSquares(int n) {
int[] dp = new int[n+1];
dp[0] = 0;
// 最坏情况初始化,最坏情况全1相加, 比如 3 = 1+1+1
for (int i = 1; i <= n; i++) {
dp[i] = n;
}
for (int i = 1; i <= n; i++) {
// 对所有可能的完全平方数,取最小的
// 例如对于 i = 12 来说,可能的 j 为 1*1【1】、 2*2【4】、 3*3【9】
// 那么就在 dp[i-1*1] 、 dp[i-2*2]、 dp[i-3*3] 三个结果中选最小的
for (int j = 1; j*j <= i; j++) {
dp[i] = Math.min(dp[i], dp[i-j*j] + 1);
}
}
return dp[n];
}