思路:动态规划,最初想到的公式是:
后来提交之后报出超时错误,因此参考了题解,找到正确的公式为:
第二个公式直接计算“前段”为平方数的情况,比起第一个公式,时间复杂度从n^2降低到n^1.5;
因此,仅仅写出动态规划的公式是不够的,需要保证:
(1)公式的正确性;
(2)公式的高效性,此一条跟题目有关。
详细分析题目中可以用来降低时间复杂度的题点,吃一堑长一智~。
代码1. 循环写法:
public int numSquares(int n){
if(n<=0) return 0;
int[] fn=new int[n+1];
fn[0]=0;
fn[1]=1;
//填充数组的过程
for(int i=2;i<n+1;i++){
int min=i;
for(int j=1;j*j<=i;j++){
if(min>1+fn[i-j*j]) {
min = 1 + fn[i - j * j];
}
}
fn[i]=min;
}
return fn[n];
}
代码2. 递归写法:
public static int numSquares(int n) {
if(n<=0) return 0;
int[] fn=new int[n+1];
fn[0]=0;
fn[1]=1;
//开始递归
numSquaresCore(n,fn);
//获得结果
int answer=fn[n];
return answer;
}
public static int numSquaresCore(int index,int[] fn){
//解决已知情况
if(index<=0) return 0;
if(index==1) return 1;
if(fn[index]!=0) return fn[index];
//最大不会超过index个,就是index=1+1+...+1的情况
int min=index;
int border=(int)(Math.pow(index,0.5)+0.5);
for(int i=1;i<=border;i++){
if(index-i*i==0){
//当前为平方数
min=1;
}
else if(index-i*i>0){
//减掉i*i,然后计算剩余的子问题
if(fn[index-i*i]==0){
fn[index-i*i]=numSquaresCore(index-i*i,fn);
}
if(min>1+fn[index-i*i]){
min=1+fn[index-i*i];
}
}
}
fn[index]=min;
return min;
}