完全平方数
给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。
完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。
示例 1:
输入:n = 12
输出:3
解释:12 = 4 + 4 + 4
示例 2:
输入:n = 13
输出:2
解释:13 = 4 + 9
提示:
1 <= n <= 104
这一题我觉得其实比我做的上一题 322. 零钱兑换 更加简单,
因为这个没有不存在的情况,因为有万能1的存在,怎么凑都可以凑够!
我认为这个只是多出一步需要自己求出,n以内的完全平方数,就可以转换成一个和322. 零钱兑换类似的问题,并且更简单考虑的情况更少!
首先第一个问题,我们如何求n以内完全平方数
// step 0 求n以内的完全平方数
int[] square=new int[n/2];
int l=1;
square[0] = 1;
for (int i=2;i<n;i++){
if(i*i>n) break;
square[i-1] = i*i;
l++;
}
解下来就转化成了01背包问题,假设n=12,其完全平方数数组为x={1,2,4,9}
其实也就是用{1,2,4,9}里面最少的数去凑满12即可!
定义dp数组及其下标含义
dp[j] : 表示使用了完全平方数组去凑满j使用的完全平方数的最少个数
初始化dp数组
dp[0]=0; 保证 dp[j-x[i]] x[i]==j时 dp[j] = 1;
dp[1]=1;
其余dp[j] = Integer.Max;
状态转移方程
遍历x,选择最小的dp[j] = dp[j - x[i]]
public int numSquares(int n) {
// step 0 求n以内的完全平方数
int[] square=new int[n/2];
int l=1;
square[0] = 1;
for (int i=2;i<n;i++){
if(i*i>n) break;
square[i-1] = i*i;
l++;
}
if(l<=1) return n;
// step 2 创建dp数组
int[] dp=new int[n+1];
// step 3 初始化dp数组
dp[0]=0;
dp[1]=1;
for (int i=2;i<dp.length;i++){
dp[i] =Integer.MAX_VALUE;
}
// step 4 完善dp数组
for (int j=2;j<dp.length;j++){
for (int num : square){
if(num<=j){
dp[j]=Math.min(dp[j],dp[j-num]+1);
}
}
}
// print Dp
for (int i=0;i<dp.length;i++){
System.out.println("dp "+i+","+dp[i]);
}
return dp[dp.length-1];
}
其获取>n的完全平方数,完全可以在循环中进行
public int numSquares2(int n) {
// step 2 创建dp数组
int[] dp=new int[n+1];
// step 3 初始化dp数组
dp[0]=0;
dp[1]=1;
for (int i=2;i<dp.length;i++){
dp[i] =Integer.MAX_VALUE;
}
// step 4 完善dp数组
for (int j=2;j<dp.length;j++){
//step 0 求n以内的完全平方数
for (int i=1;i*i<=j;i++){
int num=i*i;
if(num<=j){
dp[j]=Math.min(dp[j],dp[j-num]+1);
}
}
}
// step 5 print Dp
for (int i=0;i<dp.length;i++){
System.out.println("dp "+i+","+dp[i]);
}
return dp[dp.length-1];
}