計算第n個斐波那契數


方法一:傳統遞歸法

時間復雜度O(2^n),空間復雜度O(n)

計算Fibonacci(10)十次平均用時0.0003s    計算Fibonacci(100)單次用時大於1min

時間復雜度極高,當n>35左右時間已經無法接受

def Fibonacci(n): if n == 1 or n == 2: return 1 return Fibonacci(n - 1) + Fibonacci(n - 2)

方法二:動態規划法

時間復雜度O(n),空間復雜度O(1)

計算Fibonacci(10)十次平均用時小於0.00001s    計算Fibonacci(100)十次平均0.0001s    計算Fibonacci(10000)十次平均0.008s    計算Fibonacci(1000000)十次平均9.525s

def Fibonacci(n): current, pre = 1, 0 for i in range(n - 1): current, pre, = current + pre, current return current

方法三:通項公式法

時間復雜度O(log n),空間復雜度O(1),通項公式法的時間復雜度不是O(1),這是因為計算n次冪不能做到O(1)時間復雜度,使用快速冪算法可以做到(log n)時間復雜度

計算Fibonacci(10)十次平均用時小於0.00001s    計算Fibonacci(100)十次平均用時小於0.00001s

計算Fibonacci(10000)數字太大,出現OverFlow錯誤    計算Fibonacci(1000000):數字太大,出現OverFlow錯誤

 由於開方和四舍五入存在精度誤差,經過測試,使用通項公式法計算斐波那契數列在第71項時開始出現精度導致的計算錯誤。

根據測試可知,通項公式法只在理論上可行,沒有操作性。

def Fibonacci(n):
    sqrt5 = 5 ** 0.5
    ans = (((1 + sqrt5) / 2) ** n - (((1 - sqrt5) / 2) ** n)) / sqrt5
    return round(ans)

方法四:矩陣法

主要原理是以下公式和快速冪算法

這種算法是求任意線性常系數遞歸遞推關系的任意項的通用解法,而且通常也是最優解

時間復雜度O(log n),空間復雜度O(log n)(由遞歸深度決定)

計算Fibonacci(10)十次平均用時0.0002s    計算Fibonacci(100)十次平均0.0003s    計算Fibonacci(10000)十次平均0.0008s    計算Fibonacci(1000000)十次平均0.184s

可以看出當n較大時,矩陣法明顯優於動態規划法

另外,在這個方法中,使用了Strassen算法算法計算矩陣的乘法(該算法可以使得兩個大小為n的方朕相乘的時間復雜度由傳統的O(n ^ 3)下降到O(n ^ 2.81))

同時在快速冪算法中使用了一定的位運算技巧以達到最優化的性能

(筆者同時測試了把快速冪的遞歸算法換成非遞歸算法,非遞歸算法的時間大概是遞歸算法的兩倍)

def Matrix_Multiply(matrix1, matrix2):
    a, b, c, d = matrix1[0][0], matrix1[0][1], matrix1[1][0], matrix1[1][1]
    e, f, g, h = matrix2[0][0], matrix2[0][1], matrix2[1][0], matrix2[1][1]
    p1 = a * (f - h)
    p2 = (a + b) * h
    p3 = (c + d) * e
    p4 = d * (g - e)
    p5 = (a + d) * (e + h)
    p6 = (b - d) * (g + h)
    p7 = (a - c) * (e + f)
    r = p5 + p4 - p2 + p6
    s = p1 + p2
    t = p3 + p4
    u = p5 + p1 - p3 - p7
    return [[r, s], [t, u]]


def Matrix_Quick_Pow(matrix, p):
    if p == 1:
        return matrix
    if p & 1:
        temp = Matrix_Quick_Pow(matrix, p >> 1)
        return Matrix_Multiply(Matrix_Multiply(temp, temp), matrix)
    else:
        tmp = Matrix_Quick_Pow(matrix, p >> 1)
        return Matrix_Multiply(tmp, tmp)


def Fibonacci(n):
    matrix = [[1, 1], [1, 0]]
    return Matrix_Quick_Pow(matrix, n)[0][1]


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM