斐波那契數列指的是這樣一個數列:1,1,2,3,5,8,13,21……
這個數列從第三項開始,每一項都等於前兩項之和。它的通項公式爲:(1/√5)*{[(1+√5)/2]^n - [(1-√5)/2]^n}【√5表示根號5】
斐波那契數列按照其遞推公式可簡單寫出遞歸算法:
int fib1(int n) {
if(n == 1 || n == 2)
return 1;
return fib1(n-1)+fib1(n-2);
}
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
首先是數據範圍問題,用long型存儲結果數據與用int型同樣僅能計算到第46項,第47項開始數據溢出,即便用unsigned long也只能算到47而已。考慮使用字符模擬大整數運算的方法來處理。
其次的運算效率問題,第40項開始已經有明顯的等待時間,第46項需等待數秒才能算出結果。
需考慮其他算法。
可以考慮簡單的動態規劃,開一個數組存儲計算過的數據,避免重複運算,可大幅提高效率(即空間換時間),效率接近線性。但遞歸算法當計算項數很大是會由於遞歸過深導致遞歸棧溢出。
直接開數組通過循環進行遞推運算可避免遞歸過深問題:
int fib2(int n, int f[]) {
f[0] = f[1] = 1;
for(int i = 2; i < n; i++) {
f[i] = f[i-1] + f[i-2];
}
return f[n-1];
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
但是數組難以存儲大數,用字符串數組存儲又過於浪費空間。
例如,長度爲4的地面一共有如下5種鋪法:
4=1+1+1+1
4=2+1+1
4=1+2+1
4=1+1+2
4=2+2
編程用遞歸的方法求解上述問題。
4
int n = scanner.nextInt();
int [] arr = new int [n+1];
arr[0]=1;arr[1]=1;
for (int i = 2; i < arr.length; i++) {
arr[i] = arr[i-1] + arr[i-2];
}
System.out.println(arr[n]);
}
}