a*算法的时间复杂度_三种时间复杂度算法求解斐波那契数列

v2-4b67911724577b5f402d54e540aed10b_1440w.jpg?source=172ae18b

0. 问题描述

在数学当中,由斐波那契数字(Fibonacci number,记作

)构成的序列,被称为斐波那契数列(Fibonacci sequence)。该数列中的每一个数字等于排在它前面的两个数字之和。
  • 数列从0和1开始:
    ,
  • 数列第n个(n>1)数字为:

按照上述公式,计算得到斐波那契数列为:

随着n的增大,斐波那契数列增长比例逐渐趋近于黄金分割比例。

本文将尝试使用三种时间复杂度不同的算法求解该序列的第n个数字,分别为:

  1. 递归法:时间复杂度
  2. 循环法:时间复杂度
  3. 矩阵连乘法:时间复杂度
    (?有待商榷)

1. 递归解法

从斐波那契数列的计算公式:

,可自然想到该问题适合使用递归法求解,下面直接给出python代码。
def 

时间复杂度分析

细心的读者应该能观察到递归求解的过程如同构造一棵二叉树,例如求解

依赖
,我们把
作为树的根节点,
作为左右两个叶子节点,继续向下递归,左节点
继续向下分解为
,右节点
继续向下分解为
,依此类推,如下图所示:

v2-ecfe6a7f66023f043649b69279dc90b5_b.jpg

因此,该算法的时间复杂度为

性能优化

指数级的复杂度太高,在

较大时响应时长无法接受,幸好存在优化的空间。从上面的二叉树中可以发现,存在大量重复的节点。优化的方法是把计算过的结果存放在字典中,每次计算前查看字典中是否已经存在相同的节点,如果有则直接返回,否则将此新节点存放在字典中,优化后的程序如下。
dic 

优化后的程序相当于给之前的递归树做了剪枝操作,相同的节点仅执行一次,因此时间复杂度降为

2. 循环解法

如果说前面的递归解法是自顶向下将大问题拆解成小问题求解,那么循环解法则是逆向思维,自底向上,先求出小问题的解,再向上一步一步向上求取最终问题的解。

v2-2e869d05c52fb10d5a1859f807a0d488_b.jpg

求解过程分为

步,将每一步的结果保存在列表中对应下标的位置,代码如下。
def 

时间复杂度分析

单层循环,时间复杂度为

,与优化后的递归解法复杂度相当。

性能优化

时间复杂度已经没有优化空间了,但可以使用两个临时变量替换掉长度为

的列表,使空间复杂度从
降为
。代码如下:
def 

3. 矩阵连乘法

根据斐波那契数列自身的性质,我们可以构造如下方等式关系:

使用矩阵表示上述等式关系,即

那么

依次乘下去,可得一般形式

我们要求解的

即为向量
的第一个分量。代码如下:
import 

时间复杂度分析

从程序上看,结果result几乎是一条语句返回的,这样看时间复杂度为

。但语句涉及到乘方运算,即n个矩阵相乘,时间复杂度似乎又是
。这一结论有待商榷。

性能优化

将矩阵对角化后,再进行连乘操作,可大大提升运算效率。对角化方法为

,其中
是要被对角化的矩阵,
为由
的特征向量组成的矩阵,
为由
的特征值构成的对角矩阵。

,python代码如下:
import 

问题

NumPy在处理矩阵乘法时会进行大量的浮点运算,在

时,结果的精度有损失。

4 小结

  • 经实际运行测试,不使用字典的递归算法在
    时几乎慢到不可用的程度。
  • 使用字典优化后的递归算法与循环算法性能相当,使用
    测试运行时长大概在万分之一秒。
  • 矩阵连乘算法虽看似简单,但运行效率不如循环算法,运行时长大概在千分之一秒,且矩阵对解化操作并没有带来明显的性能提升。
  • 最终的运行效率排序为:循环法
    递归(带字典)
    矩阵连乘
    递归(不带字典)。

参考

[1] WikiPedia: Fibonacci number

[2] MIT线性代数: 矩阵对角化(网易公开课)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值