python求斐波那契数 Python求斐波那契数列之和_python斐波那契数列前20项


……续上回

前面说的都是计算一个斐波那契数列中的数

这篇来谈谈生成斐波那契数列前n项及探讨下时间复杂度

13. 生成数列的for迭代解法

先给出程序


import numpy
from gmpy2 import mpz

def Fibonacci_sequence_11 (n: int) -> list:  #参数n是表示求n项Fibonacci数列
    '返回列表的for迭代解法'
    assert isinstance(n, int), 'n is an error of non-integer type.'
    
    if n>=2:
        fib_list = numpy.empty(n + 1, numpy.object)
        fib_list[0] = mpz(0); fib_list[1] = mpz(1)
        for i in range(2, n+1):
            fib_list[i] = fib_list[i - 1] + fib_list[i - 2]
        return fib_list
    elif n==1:
        return numpy.array([mpz(0), mpz(1)])
    elif n==0:
        return numpy.array([mpz(0)])
    else:
        return None


生成数列前n项,那算法时间复杂度的下限就是O(n)

这迭代解法是不是呢

从表面上看这算法时间复杂度是O(n),循环N次两个数的加法

然而

但是,一旦数的范围扩展到大数,就不能认为两数相加是个常数时间复杂度了

两大数相加会被分段相加,大整数二进制位长为k,那么大整数相加时间复杂度也就是O(k)

如前篇所说,第n项斐波那契数的二进制位长k跟n是线性关系

带入上面的迭代解法,那这迭代解法的时间复杂度就是O(n^2)

好好的O(n)算法,遇上大数就悲剧了,成了至少O(n^2)时间复杂度

那下面再看之前最快的两种生成斐波那契数算法在生成数列效率如何

14. 生成数列的GMP内置fib2函数解法


import gmpy2
def Fibonacci_sequence_19 (n: int) -> list:  #参数n是表示求n项Fibonacci数列
    '返回列表的GMP内置fib函数解法'
    assert isinstance(n, int), 'n is an error of non-integer type.'
    if n>=0:
        fib_list = []
        for i in range(n, 0, -2):
            fib_list.extend(gmpy2.fib2(i))
        if n & 1 == 0:
            fib_list.append(gmpy2.mpz(0))
        fib_list.reverse()
        return fib_list
    else:
        return None


因fib2的时间复杂度是O(n*(log n)^2)

那代入这O(n)循环,此解法时间复杂度为O(n^2*(log n)^2)

15. 生成数列的二分递归解法

大数运算部分用了gmpy2库


from gmpy2 import mpz
def Fibonacci_sequence_17 (n: int) -> list:  #参数n是表示求n项Fibonacci数列
    assert isinstance(n, int), 'n is an error of non-integer type.'
    cache = dict()

    def Calculate_Fibonacci_sequence (n: int) -> int:
        '返回列表的二分递归解法'
        nonlocal cache

        if n in cache:
            return dict.get(cache, n)
        else:
            if n >= 2:
                one_half_n = n >> 1
                one_half_fib_n = Calculate_Fibonacci_sequence(one_half_n)
                if n & 1 == 0:  #当n为偶数项
                    one_half_fib_n_minus_one = Calculate_Fibonacci_sequence(one_half_n - 1)
                    results = (one_half_fib_n_minus_one * 2 + one_half_fib_n) * one_half_fib_n
                else:  #当n为奇数项
                    one_half_fib_n_add_one = Calculate_Fibonacci_sequence(one_half_n + 1)
                    results = one_half_fib_n ** 2 + one_half_fib_n_add_one ** 2
                cache.update({n: results})
                return results
            elif n == 1:
                cache.update({1: mpz(1)})
                return mpz(1)
            elif n == 0:
                cache.update({0: mpz(0)})
                return mpz(0)
    if n >= 0:
        for i in range(n, 1, -1):
            if i not in cache:
                Calculate_Fibonacci_sequence(i)
        fib_list=[None] * (n + 1)
        for i in range(n+1):
            fib_list[i] = dict.get(cache, i)
        return fib_list
    else:
        return None


时间复杂度分析,最外层循环是O(n),内层调用Calculate_Fibonacci_sequence因为被全局缓存,在外层n次调用完成不会超过n次,所以是O(1),大整数运算是O(n*log n)

这解法时间复杂度就为O(n^2*log n)

比用GMP内置fib函数生成数列时间复杂度更低

我算法课学得不好,以上如果有错误还望大佬们给指出