斐波那契數列是學習演算法碰到的,以自己當前的知識面還不足以想到通過公升高乙個維度來降低演算法的時間複雜度.
昨天再看劍指offer的時候,在面試題9中提到了三種實現計算斐波那契數列的方法.在這裡實現三種做法貌似還有乙個o(1)的計算方法,也就是斐波那契數列是可以直接推到出來的.
1.常規的遞迴演算法
def fib(n):
if n <= 0:
return 0
if n == 1:
return 1
return fib(n - 1) + fib(n - 2)
print (fib(5))
這種遞迴演算法有大量的重複計算
以f(4)為例
f(4) = f(3) + f(2) ;
f(3) = f(2) + f(1)
f(2) = f(1) + f(0)
時間複雜度是以指數的形式增長,o(2^n)
如果面試時候這樣寫,90%的概率你已經gg了
2.迴圈形式
遞迴主要是做了大量的重複計算,如果把每一項計算出來後直接儲存,使用的時候再去呼叫,這樣就減少那些不必要的計算.
def f(n):
a, b = 0, 1
while n:
a, b = b, a + b
n -= 1
return a
print (f(4))
只要記錄好前面的,後面的計算就直接用了.時間複雜度是o(n)
3.以矩陣的形式計算
就是通過增加維度降低時間複雜度
可以通過數學歸納法得出
[[f(n), f(n - 1)], [f(n - 1), f(n - 2)]] = [[1, 1], [1, 0]]^(n - 1)
所以得出這個結論之後,要做的就是計算計算矩陣[[1,1], [1,0]]^(n - 1)
這可以考慮
a^n = a^(n /2 ) * a^(n / 2) if n % 2== 0
a^n = a^ (n - 1) * a^ (n - 1) * a if n%2 != 0
得到這些資訊,就可以計算了
def mul(l1, trix):
return [sum(list(map(lambda x:x[0] * x[1], zip(l1, trix[:][0])))),\
sum(list(map(lambda x:x[0] *x[1], zip(l1, trix[:][1]))))]
def matrixmulti(trix1, trix2):
return [mul(trix1[0], trix2), mul(trix1[1], trix2)]
def main(n):
basicmatrix = [[1, 1], [1, 0]]
# 單位1
ans = [[1, 0], [0, 1]]
if n == 0:
return 0
if n == 1:
return 1
while n:
# n是奇數,先做乙個乘法
if n&1:
ans = matrixmulti(ans, basicmatrix)
basicmatrix = matrixmulti(basicmatrix, basicmatrix)
n >>= 1
return ans[0][1]
for i in range(10):
print (main(i))
就可以得到最終的結果
這種基於遞迴用o(log(n))的求得n次方的方法值得重視.
三種方法實現斐波那契數列
問題描述 編寫程式在控制台輸出斐波那契數列前t項,每輸出5個數換行 第一種方法 耗時比較短 publicstaticvoidtest1 long t longend system.currenttimemillis system.out.println end start 第二種方法 耗時太長沒有測...
實現斐波那契數列的三種方法
斐波那契數列又稱 分割數列。它的特點是從第3個數開始,每乙個數都等於前面兩個數相加。例 0 1 1 2 3 5 8 13 21.從上我們可以總結出以下規律 當n 0時 f n 0 當n 1時 f n 1 當n 1時 f n f n 1 f n 2 那我們如何求出這個數列中第n個數是多少呢?一 以指標...
實現斐波那契數列的三種方式
首先說說斐波那契數列 從文字上說,斐波那契數列由0和1開始,之後的斐波那契係數就由之前的兩數相加,數列形式如下 0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,在數學上,是以遞迴的方法來定義 f 0 0 f 1 1 f n f n...