微軟面試題之一,難度係數中。
題目描述如下:
定義fibonacci 數列如下:
/ 0 n=0
f(n)= 1 n=1
\ f(n-1)+f(n-2) n=2
輸入n,用最快的方法求該數列的第n 項。
邏輯分析:
對於斐波那契數列問題,經常在各種語言書中,作為遞迴的例子,所以提起遞迴,很多程式設計師都會想到斐波那契數列,至於效率嘛。。。呵呵,***,順便一提,這貨也是讓大部分人不假思索,直言一切遞迴低效率的罪魁禍首。
這裡給出坑爹的遞迴演算法實現原始碼:
int fibonacci(int n)
該演算法效率低下的本質原因在於重複計算,我們以n=10為例,
f(10)/ \
f(9)
f(8)/\
/ \f(8)
f(7)
f(7)
f(6)/ \
/\f(7)
f(6)
f(6) f(5)
可以看出,樹中的所有節點都需要計算,而顯而易見的是,樹中存在重複節點,樹的高度為n-1,則時間複雜度為o(2^n)(等比數列求和)。
補充:這裡的計算是估算,因為並非是滿二叉樹,嚴格來講,這裡只是得到了演算法的複雜度階——指數複雜度。
這裡摘出資料結構經典書籍中的一段分析:
我們令t(n)
為函式fib(n)
的執行時間,當
n>=2
的時候我們分析可知:
t(n) = t(n-1) + t(n-2) + 2
而fib(n) = fib(n-1) + fib(n-2)
,所以有
t(n) >= fib(n)
,歸納法證明可得:
fib(n) < (5/3)^n
當
n>4
時,fib(n
)>= (3/2)^n
標準寫法:
顯然這個o
((3/2)^n
)是以指數增長的演算法
,基本上是最壞的情況。
其實,這違反了遞迴的乙個規則:合成效益法則。
合成效益法則(
compound interest rule
):在求解乙個問題的同一例項的時候,切勿在不同的遞迴呼叫中做重複性的工作。
所以在上面的**中呼叫
fib(n-1)
的時候實際上同時計算了
fib(n-2)
。這種小的重複計算在遞迴過程中就會產生巨大的執行時間。
2、找到了問題的所在,那麼我們的想法,顯然就是避免重複計算,實際上,不難想到,只要利用乙個迴圈,不斷遞推,便可以在o(n)的時間複雜度內完成演算法。
int fibonacci(int n)
; if(n<2)
return result[n];
int fibone = 1,fibtwo = 0;
int fibn = 0;
for(int i=2;i<=n;i++)
return fibn;
}
3、題目要求時間複雜度盡可能低,而作為面試題,顯然o(n)並非最佳解。到目前為止,我們成功避免了重複計算,那麼,如果我們想進一步降低時間複雜度,就要從數學上刪繁就簡,得到乙個最純粹的式子,而對於數列來說,只要寫出通項公式,那麼對於計算機來說,時間複雜度基本上可以看做是o(1),斐波那契數列通項公式的求法,這裡就不再多說,對於只要有一點高中數學競賽基礎的看客,想必並非難事。
**實現:
int fibonacci(int n)
注:實際上,雖然理論上時間複雜度是o(1),不過效率上還是和具體的pow,sqrt函式有關係。
4、我想對於大部分人來說,問題做到這裡,就可以結題了。不過對於斐波那契數列問題,一部分人是了解一種矩陣演算法的(我記著好像是在mit演算法導**開課看到的。。。)
我們將數列寫成:
fibonacci[0] = 0,fibonacci[1] = 1
fibonacci[n] = fibonacci[n-1] + fibonacci[n-2] (n >= 2)
可以將它寫成矩陣乘法形式:
遞推得到:
那麼,我們的目標,就是計算
問題的精髓便在於此處,我們分離出了目標,但是直觀上需要計算n次方,單純的迴圈計算,時間複雜度上並不會有所改善,依然是o(n),而對於乘方計算這一問題,實際上也是歷史悠久,沒錯,你應該想到了,利用二分法,演算法五大思想中的分治。
乘方性質: /
a^(n/2)
*a^(n/2)
n為偶數時a^n
=\ a^((n-1)/2)*a^((n-1)/2)*a
n為奇數時
求n次方,那麼先求得n/2次方,再將結果平方一下,所以,時間複雜度o(logn)。
#include #include //2x2矩陣結構體定義
struct matrix2by2
int m_00;
int m_01;
int m_10;
int m_11;
};//矩陣乘法運算
matrix2by2 matrixmultiply
( const matrix2by2& matrix1,
const matrix2by2& matrix2
)///
//計算矩陣的n次方
// 1 1
// 1 0
///matrix2by2 matrixpower(unsigned int n)
else if(n % 2 == 0)
else if(n % 2 == 1)
return matrix;
}//斐波那契呼叫介面
斐波那契數列 斐波那契數列python實現
斐波那契數列 fibonacci sequence 又稱 分割數列 因數學家列昂納多 斐波那契 leonardoda fibonacci 以兔子繁殖為例子而引入,故又稱為 兔子數列 指的是這樣乙個數列 1 1 2 3 5 8 13 21 34 在數學上,斐波納契數列以如下被以遞推的方法定義 f 1 ...
迴圈斐波那契數列 斐波那契數列應用
什麼是斐波那契數列 斐波那契數列指的是這樣乙個數列 1,1,2,3,5,8,13,21,34,55,89,144 這個數列從第3項開始,每一項都等於前兩項之和 台階問題 有一段樓梯有10級台階,規定每一步只能跨一級或兩級,要登上第10級台階有幾種不同的走法?這就是乙個斐波那契數列 登上第一級台階有一...
斐波那契數列
1 題目描述 大家都知道斐波那契數列,現在要求輸入乙個整數n,請你輸出斐波那契數列的第n項。斐波那契數列的定義如下 輸入 輸入可能包含多個測試樣例,對於每個測試案例,輸入包括乙個整數n 1 n 70 輸出 對應每個測試案例,輸出第n項斐波那契數列的值。2 這是九度上的乙個題,要求時間限制1秒,整數的...