斐波那契數,通常用f(n)表示,形成的序列稱為 斐波那契數列 。該數列由 0 和 1 開始,後面的每一項數字都是前面兩項數字的和。也就是:
f(0) = 0,f(1) = 1
f(n) = f(n - 1) + f(n - 2),其中 n > 1
給你 n ,請計算 f(n) 。
示例 1:
輸入:2
輸出:1
解釋:f(2) = f(1) + f(0) = 1 + 0 = 1
遞迴有兩個基本要素:基例以及遞迴關係式。
def
fib(n)
:#base case
if n <=1:
return n
elif n >=2:
return fib(n-1)
+ fib(n-
2)
然後根據python語法特性,可以縮寫為一句話
def
fib(n)
:return fib(n-1)
+ fib(n-2)
if n >=
1else n
f(20) = f(19)+f(18)
f(19) = f(18)+f(17)
然後我們發現 f(18) 重複,即冗餘結構。這樣的運算時間會很大,
節點數 * 每個子問題所需要的時間 = 時間複雜度
顯而易見,這種情況下為o(2^n)
純遞迴的缺點就在於存在過多冗餘結構。
遞迴加記憶,將指數級時間將為多項式級時間。
我們可以將已經出現計算好的存在乙個備忘錄裡面,這樣我們下一次計算之前,先去查一遍表就行,不需要再重新計算。
memo =
deffib
(n):
#查表if n in memo:
return memo[n]
#base case:
elif n <=1:
return n
else
: ans = fib(n-1)
+ fib(n-2)
memo[n]
= ans
return memo[n]
當然,上述的備忘錄既可以採用陣列,同時也可以用雜湊表。
另外,如果追求完美一點,可以將基例儲存到備忘錄裡面,這樣可以減少一定程度的空間複雜度。
memo =
這裡介紹的是由上而下的方法,當然也可以是由下而上的。雖然比純遞迴好,但是時間複雜度依然很高,leetcode上為1500-1600ms左右。
bottem-up-solution
def
fib(n)
: memo =
for i in
range(2
,n+1):
memo[i]
= memo[i-1]
+ memo[i-2]
return memo[n]
for迴圈的左邊是因為備忘錄裡面已經有鍵0,1了,所以從2開始。然後我們最後要計算的是memo[n],i = n 所以要為n+1
這個的時間複雜度會大大降低,兩者看似都是查表,但是由下而上的這種不會重新迭代函式,只會不斷計算表。leetcode資料為36ms
演算法方面的優化到此為止,但是關於空間複雜度可以更優化一點,
import sys
h =l =[0
,1]print
(sys.getsizeof(h)
)print
(sys.getsizeof(l)
)#232
#72
字典的空間複雜度遠大於列表,所以可以更優化一點。單方面來講,複雜度跟元素大小無關。跟元素個數有關。
def
fib(n)
:if n ==0:
return
0 memo[
1for i in
range
(n+1)]
memo[0]
,memo[1]
=0,1
for i in
range(2
,n+1):
memo[i]
= memo[i-1]
+ memo[i-2]
return memo[n]
關於第一行生成len = n+1的原因,因為最後返回索引為n,而索引從0開始
而且除了列表生成器的表達,還可以
memo = [1] * (n+1)
之所以提取生成長度為n+1的列表,是為了防止列表索引不夠,進行有序的替換。
因為是替換的,所以初始化列表的值是任取的,只要保證基例正確就行。
要小心的是,如果輸入0沒有開頭的if語句是會報錯的(for 迴圈)
還有就是力扣的很多時候判別的不准,大家只要往死裡優化,看看幾個最優解就行。不必苛求100%,大家可以複製幾個100%,有些是運氣100%,到你這就不是100%
最後,作為拓展,還有一種滾動變數的方法。
def
fib(n)
:if n ==0:
return
0for i in
range
(n):
a,b = b,a+b
return a
這種方法顯然不是最優解,但是值得一說的是,按照一些書中python的**規範。這種結構可讀性不好,建議少用。
大家覺得好的話,可以去github上給我點小星星呦
斐波那契數列 斐波那契數列python實現
斐波那契數列 fibonacci sequence 又稱 分割數列 因數學家列昂納多 斐波那契 leonardoda fibonacci 以兔子繁殖為例子而引入,故又稱為 兔子數列 指的是這樣乙個數列 1 1 2 3 5 8 13 21 34 在數學上,斐波納契數列以如下被以遞推的方法定義 f 1 ...
Python演算法 斐波那契數列
典型的遞迴演算法 快速排序會用到 先做個鋪墊 斐波那契數列即著名的兔子數列 1 1 2 3 5 8 13 21 34 數列特點 該數列從第三項開始,每個數的值為其前兩個數之和,用python實現起來很簡單 定義fibonacci數列如下 非遞迴方法的函式實現 def fibs num result ...
Python斐波那契數列演算法
第一種 函式求裴波那契數列 def func num if n 1 or n 2 如果n等於1或者2 return 1 返回1 else 否則 return func n 1 func n 2 返回函式n 1加上函式n 2的值 print func 12 輸出第12個裴波那契數列的數第二種 用類求裴...