算法一---斐波那契數列

題目

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個數要執行多少次?
要執行1+2+4+8+...+2n2=2n2

時間複雜度:O(2N )

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)f(n1)]=[1110][f(n1)f(n2)]

我們通過不斷迭代,很顯然能得出公式:
[f(n)f(n1)]=[1110]n2[f(2)f(1)]

所以要求f(n),只需要求出矩陣
[1110]n2

的值就行了。

計算二階矩陣的N次冪運算,由於二階矩陣乘法滿足結合律,這樣,可以快速計算二階矩陣的n次冪運算。

假設A爲一個二階矩陣,則A的冪運算滿足下面的條件:

A6=A3A3

A7=A3A3A1=A4A2A1

在這裏,我們可以類似地把A看做是二進制中的2,27=242221 也就是說可以把矩陣的冪轉換成二進制來表示。從而可以將n次冪拆解成長度爲logn的二進制數來表示:7=111(二進制)。

這就是快速求二階矩陣的核心方法。

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編程和活動腦筋的目的,還是決定每個星期研究個一個來玩玩。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章