python奇数数列求和_斐波那契数列与Python的尾递归蹦床 连载【7】

01f11b543559027878c995f841ca757c.png

8fe32814948142ceb57f2ad19fc48fbc.png

……续上回

fss.sosei:斐波那契数列与Python的尾递归蹦床 连载【6】​zhuanlan.zhihu.com
84e6613ebeac52a56499fc3ca618fb21.png

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

这篇来谈谈生成斐波那契数列前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函数生成数列时间复杂度更低

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

欢迎点赞、留言

未完待续……

fss.sosei:斐波那契数列与Python的尾递归蹦床 连载【8】​zhuanlan.zhihu.com
d2572084ab3301512f28b763cc4e184c.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值