1- 思路
动态规划 + 完全背包
- 完全平方数就是物品(可以无限件使用),凑个正整数n就是背包,问凑满这个背包最少有多少物品?(类似于零钱兑换的题目)
- 1- 定义 dp 数组 ,确定含义
dp[j]
:和为 j
的完全平方数的最少数量为 dp[j]
- 2- 确定递推公式
- dp[j] 可以由 dp[j - i * i] 推出, dp[j - i * i] + 1 便可以凑成 dp[j]
- 此时我们要选择最小的dp[j],所以递推公式:dp[j] = min(dp[j - i * i] + 1, dp[j]);
- 3- 初始化
- 和为 0 :dp[0]表示 和为0的完全平方数的最小数量,那么dp[0]一定是0。
- 不为 0:初始化为最大值 所以非 0 下标的
dp[j]
一定要初始为最大值,这样 dp[j]
在递推的时候才不会被初始值覆盖。
- 4- 遍历顺序
- 求组合:外层 for 遍历物品、内层 for 遍历背包。
- 求排列:外层 for 遍历背包、内层 for 遍历物品。
2- 实现
⭐279. 完全平方数——题解思路

class Solution {
public int numSquares(int n) {
int[] dp = new int[n+1];
dp[0] = 0;
int max = Integer.MAX_VALUE;
for(int i = 1 ; i <= n;i++){
dp[i] = max;
}
for(int i = 1 ; i*i <= n ;i++){
for(int j = i*i ; j<=n ;j++){
dp[j] = Math.min(dp[j],dp[j-i*i]+1);
}
}
return dp[n];
}
}
3- ACM 实现
public class numSquare {
public static int numSquare(int n ){
int[] dp = new int[n+1];
int max = Integer.MAX_VALUE;
dp[0] = 0;
for(int i = 1 ; i <=n;i++){
dp[i] = max;
}
for(int i = 1 ; i*i <= n;i++){
for(int j = i*i ; j<=n;j++){
dp[j] = Math.min(dp[j],dp[j-i*i]+1);
}
}
return dp[n];
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
System.out.println("结果是"+numSquare(n));
}
}