題目
Question1 2017年9月17日
Description:
查找斐波納契數列中第 N 個數。
所謂的斐波納契數列是指:
前2個數是 0 和 1 。
第 i 個數是第 i-1 個數和第i-2 個數的和。
斐波納契數列的前10個數字是:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34 …
分析
1.遞歸
根據題目描述就可以列出求斐波那契數列的公式:
f(n) = f(n-1) + f(n-2)
def fibonacci1(self, n):
if n == 1 or n == 2:
return n-1
else:
return self.fibonacci1(n-1) + self.fibonacci1(n-2)
分析一下,求第n個數要執行多少次?
要執行
時間複雜度:O(
2.循環
當然按照公式,一開始我們就定義兩個數,做一次n級的循環,每次循環給這兩個數重新賦值,這樣就能把執行次數維持在n的時間複雜度上:
def fibonacci2(self,n):
if n == 1 or n == 2:
return n-1
f1 = 0
f2 = 1
f3 = 1
i = 3
for i in range(i-1,n):
f3 = f2
f2 = f1 + f3
f1 = f3
re*turn f2
時間複雜度:O(N)
3.矩陣
仔細觀察一下,其實斐波那契數列前後項的關係可以用矩陣相乘實現:
我們通過不斷迭代,很顯然能得出公式:
所以要求f(n),只需要求出矩陣
的值就行了。
計算二階矩陣的N次冪運算,由於二階矩陣乘法滿足結合律,這樣,可以快速計算二階矩陣的n次冪運算。
假設A爲一個二階矩陣,則A的冪運算滿足下面的條件:
在這裏,我們可以類似地把A看做是二進制中的2,
這就是快速求二階矩陣的核心方法。
def matrix(n):
base=[[1,1],[1,0]] # 基礎矩陣
ans=[[1,0],[0,1]] # 結果矩陣
while n:
if n&1: # 取n的二進制的最後一位和1做與運算,如果最後一位是1,則進入if體內部
ans=multi(ans,base) # 如果在該位置n的二進制爲1,則計算ans和base矩陣
base=multi(base,base) # base矩陣相乘,相當於初始base矩陣的冪*2
n>>=1 # n的二進制往右移一位
return ans[0][1] # 最後獲取到的二階矩陣的[0][1]即f(n)的值
def multi(a,b): # 計算二階矩陣的相乘
c=[[0,0],[0,0]] # 定義一個空的二階矩陣
for i in range(2):
for j in range(2):
for k in range(2): # 新二階矩陣的值計算
c[i][j]=a[i][k]*b[k][j]
return c
時間複雜度:O(logN)
總結
這個是Lintcode上的入門題,原本以爲一個晚上就能寫完的,結果發現從慢到快的算法研究弄了我好幾天,最後的矩陣乘法也是網上看到的,畢竟數學荒廢好多年了。正好新學了一點點python,雖然算法題對我現在的工作感覺沒什麼幫助,本着練手python編程和活動腦筋的目的,還是決定每個星期研究個一個來玩玩。