美文网首页程序员
Fibonacci数列高效解法大全及时间复杂度分析 连载【5】

Fibonacci数列高效解法大全及时间复杂度分析 连载【5】

作者: FSS_Sosei | 来源:发表于2018-10-05 16:25 被阅读0次
    在数学上,斐波那契数列是以递归的方法来定义

    ……续上回Fibonacci数列高效解法大全及时间复杂度分析 连载【4】

    来看profile的记录分析,看时间具体用在哪个部分了

    一看,绝大部分时间耗在两句results上了

    看来主要都用来大整数运算了

    下面来试一下

    把这程序里两句“results = ”后面的大数运算注释掉,换成1。也就是两句都成“results = 1”

    再运行计时看看

    Total time: 0.000753秒

    很惊人,去掉大数运算后,运行时间缩短成了原用时的1%。也就是99%时间消耗在Python内置的大数运算上了

    下面试下用号称地球上最好的大数运算库替换掉Python内置的大数运算

    9.  应用GMP库

    全称是GNU Multiple Precision Arithmetic Library,即GNU高精度算术运算库,这是一个C写成的高效大数运算库

    gmpy2是Python下对GMP库的封装

    安装很简单,在操作系统下打命令pip install gmpy2,就安装好了

    应用到程序也很简单

    把上面的二分迭代解法程序开头添加一行

    from gmpy2 import mpz

    再把程序里

    child_nodes = (n, 1)

    child_nodes = (n, 0)

    改成

    child_nodes = (n, mpz(1))

    child_nodes = (n, mpz(0))

    就可以了

    运行看一下用时

    Total time: 0.00689297秒

    是原用Python内置大数运算用时的9%

    效果显著。可见Python内置大数运算效率确实不怎么样

    相关大整数乘法高效算法的介绍可参见这篇《【算法】大数乘法问题及其高效算法

    极大整数乘法的时间复杂度低至近似O(n*log n)

    前面二分解法本身时间复杂度是O(log n)

    现在把大数因素考虑进去。大数时间复杂度的n可以用二进制位数表示

    第n项斐波那契数的二进制位数k跟n是线性关系,n*10,那位数k也是*10

    现在把极大整数乘法时间复杂度代入,O(n*log n)*O(log n)=O(n*(log n)^2)

    也就是在大数情况下二分解法的时间复杂度为O(n*(log n)^2)

    可以看这篇《为什么算法渐进复杂度中对数的底数总为2》解释

    10.  矩阵解法

    斐波那契数列和矩阵的关系推导我看到GoCalf Blog里写的一段非常清晰,特在此引用

    http://www.gocalf.com/blog/calc-fibonacci.html

    这解法就是求矩阵的n-1次幂。矩阵幂运算也能根据下面公式迭代二分加速

    就是所谓的矩阵快速幂

    Python里库很丰富,大名鼎鼎的numpy就是一个有关矩阵的库。这库是有优化的,算矩阵幂就不用个人再写什么矩阵快速幂函数了

    用numpy库就能很简单的写出来

    因为numpy没有大数支持,大数运算还是要用GMP库

    import numpy.matlib

    from gmpy2 import mpz

    def Fibonacci_sequence_06 (n: int) -> int:  #参数n是表示求第n项Fibonacci数

        '返回单项的矩阵解法'

        assert isinstance(n, int), 'n is an error of non-integer type.'

        if n>=0:

            fib_matrix = numpy.mat(((mpz(1), mpz(1)), (mpz(1), mpz(0))))

            fib_matrix **= n-1

            return fib_matrix[0,0]

        else:

            return None

    Fibonacci_sequence_06(1000000)

    同上测用时

    Total time: 0.042466秒

    这幂运算是二分加速的,时间复杂度为O(log n)

    对于固定阶矩阵相乘,乘的次数是个常数,也就是O(1)。虽然这个常数比较大^_*

    代入大数时间复杂度,总体复杂度也是O(n*(log n)^2)

    这儿来解释下为何矩阵快速幂比二分递归解法时间常数大

    我们再来仔细看看斐波那契数列的矩阵形式:

    会发现 z 和 y 必然相等,z 没必要再计算一遍。

    t = x - y,因此 t 也没必要再计算一遍。

    只需要计算矩阵第一列的那两个元素即可:

    矩阵快速幂中两个矩阵相乘实际可分解为8次两个大整数乘法,而二分递归中只需要3次两个大整数乘法。所以二分递归时间常数小。

    未完待续……

    Fibonacci数列高效解法大全及时间复杂度分析 连载【6】

    相关文章

      网友评论

        本文标题:Fibonacci数列高效解法大全及时间复杂度分析 连载【5】

        本文链接:https://www.haomeiwen.com/subject/epuqaftx.html