完全背包
import java.util.Arrays;
class Solution {
public int numSquares(int n) {
/**
* dp[j]定义为和为j的完全平方数的最小个数
* 因为是求最小值,因此所有位置初始化为最大值
* 初始值dp[0] == 0
*/
int[] dp = new int[n + 1];
Arrays.fill(dp, n + 1);
dp[0] = 0;
/**
* 完全背包
* 本题求最小个数,因此无论是求组合还是排列都可以的
* 外循环遍历物品(完全平方数的个数),内循环遍历背包容量(n)
* 物品数最大为小于n的完全平方数的个数,即i * i <= n
* i一定要从1开始,因为dp[j - i * i]中使用的是有实际意义的i,i不仅仅是索引
*/
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];
}
}
/**
* 时间复杂度 O(n*sqrt(n))
* 空间复杂度 O(n)
*/
动态规划
class Solution {
public int numSquares(int n) {
/**
* dp[i]定义为和为i的完全平方数的最少数量
* dp[1] == 1
*/
int[] dp = new int[n + 1];
dp[1] = 1;
/**
* 如果i本身就是完全平方数,结果就是1
* 否则,和为i的完全平方数最大不会超过Math.sqrt(i)向下取整
*/
for (int i = 2; i <= n; i++) {
dp[i] = Integer.MAX_VALUE;
int max = (int) Math.sqrt(i);
if (max * max == i){
dp[i] = 1;
}
else {
/**
* j的上界为max的平方
*/
for (int j = max * max; j >= 1; j--) {
dp[i] = Math.min(dp[i], dp[j] + dp[i - j]);
}
}
}
return dp[n];
}
}
/**
* 时间复杂度 O(n^2)
* 空间复杂度 O(n)
*/
优化1——只遍历sqrt(n)次
class Solution {
public int numSquares(int n) {
int[] dp = new int[n + 1];
dp[1] = 1;
/**
* 如果i本身就是完全平方数,结果就是1
*/
for (int i = 2; i <= n; i++) {
dp[i] = Integer.MAX_VALUE;
int max = (int) Math.sqrt(i);
if (max * max == i){
dp[i] = 1;
}
else {
/**
* 对于每个i的结果来说,构成平方的数都落在[1, sqrt(i)]中
* 因此j可以只遍历sqrt(i)次
* dp[i - j * j]表示减去j * j这个平方数以后的最小个数,因此最后结果dp[i]还要加上这一个
*/
for (int j = 1; j * j <= i; j++) {
dp[i] = Math.min(dp[i], dp[i - j * j]);
}
dp[i]++;
}
}
return dp[n];
}
}
/**
* 时间复杂度 O(n*sqrt(n))
* 空间复杂度 O(n)
*/
https://leetcode-cn.com/problems/perfect-squares/