面試題 9:斐波那契數列
題目:
寫一個函數,輸入n,求斐波那契(Fibonacci)數列的第n項。斐波那契數列的定義如下:
分析
首先想到的是利用遞歸來解,如:
public static int fibonacci(int n) {
if (n <=0 ) {
return 0;
} else if (n == 1) {
return 1;
} else {
return fibonacci(n - 1) + fibonacci(n - 2);
}
}
該解法確實簡單,很快就可以實現。讓我們來分析一下:
我們以求解爲例分析求解過程。想要求就的求和,想要求需要先求和,同樣想要求,又得先求和 … 我們可以以樹結構表達這種依賴關係。
不難發現,書中有很多節點重複,這意味着計算量會隨着n的增大而急劇增大,事實上,用遞歸計算的時間複雜度是以n的指數遞增的。我試了一下,當n爲45時,就能很明顯的發現獲得結果需要等待一小會兒了。
改進
上面遞歸代碼之所以慢是因爲重複計算過多,當我們的遞歸從小往大計算時,第n次的結果總是前兩次之後,而前兩次剛好再前面兩次已經計算過並記錄了。
public static void main(String args[]) {
System.out.println(fibonacci1(1000));
}
public static int fibonacci1(int n) {
int[] result = {0, 1};
if (n < 2) {
return result[n];
}
int preNumberOne = 1;
int preNumberTwo = 0;
int number = 0;
for (int i = 2; i <= n; i++) {
number = preNumberOne + preNumberTwo;
preNumberTwo = preNumberOne;
preNumberOne = number;
}
return number;
}
斐波那契數列的運用:青蛙跳臺階
題目
一隻青蛙可以跳上1級臺階,也可以跳上2級臺階。求該青蛙跳上一個n級臺階總共有多少種跳法。
分析
首先考慮最簡單的情況,如果只有一級臺階,青蛙第一次跳的時候,顯然只有一種跳法。如果有2級,有兩種跳法:一種是跳一級、一種是跳兩級。
再看一般情況,假如青蛙跳n級臺階總共有 種跳法,當n > 2 時,第一次有兩種不同的選擇:1. 只跳1級,此時跳法數據等於後面剩下的n - 1級臺階的跳法數目,即 $ F(n - 1) F(n - 2)$ 。因此n級臺階的不同跳法總數爲。不難看出,這就是一個斐波那契數列。
斐波那契數列的運用:矩形覆蓋
題目
我們可以用2 x 1的小矩形橫着或者豎着去覆蓋更大的矩形。請問用8個 2 x 1的小矩形無重疊地覆蓋一個 2 x 8的大巨星,總共有多少種方法?矩形如圖:
分析
先把2 x 8的覆蓋方法次數記爲 , 用1x2的矩形第一次覆蓋到2x8上有兩種方式:
- 豎着蓋在最左邊,此時的覆蓋次數有。
- 橫着覆蓋最左上角, 此時覆蓋次數記爲。
- 所以,對於2x8的矩形區域,
顯然,又是一個斐波那契數列。
結語
斐波那契數列相關題目特徵:
- 每個步驟有兩種不同的操作。
- 有0和1兩個解。
- 經過兩個不同操作後,問題規模將會得到不同程度的降低。