思路:動態規劃,最初想到的公式是:
後來提交之後報出超時錯誤,因此參考了題解,找到正確的公式爲:
第二個公式直接計算“前段”爲平方數的情況,比起第一個公式,時間複雜度從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;
}