给一个正整数 n, 找到若干个完全平方数(比如1, 4, 9, ... )使得他们的和等于 n。你需要让平方数的个数最少。
样例
给出 n = 12
, 返回 3
因为 12 = 4 + 4 + 4
。
给出 n = 13
, 返回 2
因为 13 = 4 + 9
。
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
|
1 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
4 |
\ |
\ |
\ |
1 |
2 |
3 |
4 |
2 |
3 |
9 |
\ |
\ |
\ |
\ |
\ |
\ |
\ |
\ |
1 |
16 |
\ |
\ |
\ |
\ |
\ |
\ |
\ |
\ |
\ |
dp[n+1][k] // k为n的开方
结合上述表格,假设n=7,
当k=1,此时为7
当k=2,此时7>4,7最多能除一个4,让7减去4 为3,此时加上dp[3][3的开方],即int amount=n/k; 比较 amount+dp[n-amount*n的开方]和dp[n][j-1](j为纵轴坐标,即和上面那个比较如果比他大,则值为上面的,相反为算出来的值)
public static int numSquares(int n) {
int k=(int)(n);
int []pingfang=new int[k+1];
for(int i=1;i<k+1;i++){
pingfang[i]=i*i;
}
int dp[][]=new int [n+1][k+1];
for(int i=1;i<n+1;i++){
dp[i][1]=i;
}
for(int i=1;i<n+1;i++){
for(int j=2;j<k+1;j++){
if(pingfang[j]>i) break;
if(pingfang[j]<=i){
int index=i/pingfang[j];
dp[i][j]=(dp[i][j-1],dp[i-index*pingfang[j]][getMin(i-index*pingfang[j])]+index);
}
}
}
return dp[n][getMin(n)];
}
public static int getMin(int n){ //求开方跟
int count=0;
for(int i=1;i<=n;i++){
if(i*i>n) break;
else{
count++;
}
}
return count;
}
在lintcode上运行,发现空间太大。想了想发现可以转换为一维数组,思路和前面一样。
dp[n] 对应的是最小值。
public static int numSquares(int n) {
int k=(int)(n);
int []dp=new int[n+1];
int []pingfang=new int[k+1];
for(int i=1;i<k+1;i++){
pingfang[i]=i*i;
}
for(int i=1;i<n+1;i++){
dp[i]=i;
}
for(int i=2;i<n+1;i++){
for(int j=2;j<k+1;j++){
if(pingfang[j]>i)continue;
if(pingfang[j]<=i) {
int index=i/pingfang[j];
dp[i]=(dp[i], dp[i-index*pingfang[j]]+index);
}
}
}
return dp[n];
}