標籤:
題目一:寫一個函數,輸入n,求斐波那契數列的第n項。斐波那契數列的定義如下:
1、效率很低效的解法,挑剔的面試官不會喜歡
很多C語言的教科書在講述遞迴函式的時候,都戶拿Fibonacci作為例子,因此很多的應聘者對這道題的遞迴解法都很熟悉。
下面是實現代碼
我們教科書上反覆用這個問題來講解遞迴的函數,並不能說明遞迴的解法最適合這道題目。面試官會提示我們上述遞迴的解法有很嚴重的效率問題要求我們分析原因。
我們以求解f(10)為例來分析遞迴的求解過程。想求得f(10),需要先求出f(9)和f(8).同樣求f(9),需要先求得f(8)和f(7)。我們用樹來構造這種依賴關係。:
我們不難發現在這顆樹中有很多的節點是重複的,而且重複的節點數會隨著n的增大而急劇增加,這意味著計算量會隨著n的增大而急劇增大。事實上,用遞迴的方法計算的時間複雜度是以n的指數的方式遞增的。讀者不妨求Fibonacci的第100項試試,感受一下這樣的遞迴會慢到什麼程度。
2、面試官期待的適用解法:
其實改進的方法比並不複雜。上述的遞迴代碼之所以慢是因為重複的計算太多,我們只要想避免重複計算就型了。比如我們可以把已經得到的數列中間項儲存起來,如果下次需要計算的時候我們先尋找一下,如果前面已經計算過就不用重複計算了。
更簡單的方法是從下往上計算,首先計算f(0)和f(1)算出f(2),再根據f(1)和f(2)算出f(3)……依次類推就可以算出第n項了。很容易理解,這種思路的時間複雜度為O(n)。實現代碼如下:
/** * 寫一個函數,輸入n,求斐波那契(Fibonacci)數列的第n項。 */package swordForOffer;/** * @author JInShuangQi * * 2015年7月29日 */public class E09Fibonacci {public long fibonacci(int n){long result =0;long preOne = 1;long preTwo = 0;if( n == 0){return preTwo;}if(n == 1){return preOne;}for(int i = 2;i<= n ;i++){result = preOne+preTwo;preTwo = preOne;preOne = result;}return result;}public static void main(String[] args){E09Fibonacci fabonacci = new E09Fibonacci();System.out.println(fabonacci.fibonacci(10));}}
3、時間複雜度O(logn)但不夠使用的解法)
通常面試到這裡就差不多了,儘管我們還有比這更快的O(logn)解法,由於這種演算法需要用到一個很生僻的數學公式,因此很少有面試官會要求我們掌握。不過以防萬一,我們還是介紹一下這種演算法。
我們先來聊i額一個數學公示:
解法比較:
用不同的方法求斐波那契數列的時間效率大不相同。第一種基於遞迴的解法雖然直觀但時間效率太低,實際軟體開發中不會使用這種方法,也不可能得到面試官的青睞。第二種方法把遞迴的演算法用迴圈來實現,極大的提高了時間效率。第三種方法把求斐波那契數列轉換成求矩陣的乘方,是一種很有創意的演算法。雖然我們可以喲個O(logn)求的矩陣的n次方,但由於隱含的時間常熟較大,很少會有軟體採用這種演算法,另外,實現這種演算法的代碼也交複雜,不太適用於面試。
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
劍指Offer面試題9(java版)斐波那契數列