傳統的遞歸實現
public long fibonacci(int n) {
if (n <= 0) {
return 0;
}
if (n == 1) {
return 1;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
但以遞歸求解的過程中會出現很多重復求解 如圖:
思路
優化方法:
- 把已得到的數列保存起來,下次計算時先查詢,已計算過就不用重復計算.
- 采用從下往上計算,可以把計算過了的保存起來,下次要計算時就不必重復計算了:先由f(0)和f(1)計算f(2),再由f(1)和f(2)計算f(3)……以此類推就行了,計算第n個時,只要保存第n-1和第n-2項就可以了。
實現
public long fibonacci(int n) {
int result[] = {0, 1};
if (n < 2) {
return result[n];
}
long fibNMinusOne = 1;
long fibNMinusTwo = 0;
long fibN = 0;
for (int i = 2; i <= n; i++) {
fibN = fibNMinusOne + fibNMinusTwo;
fibNMinusTwo = fibNMinusOne;
fibNMinusOne = fibN;
}
return fibN;
}
變種I
一只青蛙一次可以跳上1級台階,也可以跳上2級。求該青蛙跳上一個n級的台階總共有多少種跳法。
思路
將跳法總數記為f(n),可以知道f(1)=1,f(2)=2。當n>2時,第一次跳1級的話,還有f(n-1)種跳法;第一次跳2級的話,還有f(n-2)種跳法,所以可以推得f(n)=f(n-1)+f(n-2).
實現
public int JumpFloorI(int n) {
if (n ==2) {
return 2;
}
if (n == 1) {
return 1;
}
return JumpFloorI(n - 1) + JumpFloorI(n - 2);
}
變種II
一只青蛙一次可以跳上1級台階,也可以跳上2級……它也可以跳上n級。求該青蛙跳上一個n級的台階總共有多少種跳法。
思路
n級台階,第一步有n種跳法:跳1級、跳2級、到跳n級
跳1級,剩下n-1級,則剩下跳法是f(n-1)
跳2級,剩下n-2級,則剩下跳法是f(n-2)
所以f(n)=f(n-1)+f(n-2)+...+f(1)
因為f(n-1)=f(n-2)+f(n-3)+...+f(1)
兩個相減f(n)-f(n-1)=f(n-1)
所以f(n)=2*f(n-1)
實現
public int JumpFloorII(int n) {
if (n == 1) {
return 1;
} else {
return 2 * JumpFloorII((n - 1));
}
}
變種III
我們可以用21的小矩形橫着或者豎着去覆蓋更大的矩形。
請問用n個21的小矩形無重疊地覆蓋一個2*n的大矩形,總共有多少種方法?
思路
- target= 1大矩形為2*1,只有一種擺放方法,return1;
- target= 2 大矩形為2*2,有兩種擺放方法,return2;
- target= n時候第一次擺放有兩種方式
因為,擺放了一塊12的小矩陣,對應下方的12,擺放方法就確定了,所以為f(targte-2)
此解來自牛客網Follow
實現
public int RectCover(int target) {
if (target < 1) {
return 0;
}
if (target == 1) {
return 1;
}
if (target == 2) {
return 2;
}
return RectCover(target - 1) + RectCover(target - 2);
}