fibonacci数列_算法之Fibonacci数列及其变种

79b1c87eb142424d797c6dc36791ade7.png

主要内容:1. 基于Python3的Fibonacci数列生成算法比较(递归与循环),2. 基于Fibonacci数列的变种应用。并主要涉及LeetCode、牛客网和剑指Offer等内容。

当当当当,请先欣赏这张漂亮的动图:


关于Fibonacci数列,想必大家都应该比较熟悉了。定义一个数组的前两个元素分别为[0, 1] (有时候也会定义前两项为[1, 1],大同小异无需做可以区分),然后开始通项公式的向下迭代:F[n] = F[n-1] + F[n-2] (n大于2)。

因此,写出来前几项即为 [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...] 。采用图示绘制出来,如上图中的螺旋状。

在编程语言学习中,Fibonacci数列的实现,也常常是非常经典的题目。下面,我们先检索下LeetCode、牛客网和《剑指Offer》相关题目,然后就开始用Python实现:

1)递归

由其通项公式可知,每项均可由前两项相加得到,然后可以继续递归分解。

LeetCode #509 提交后给出的评估:

Runtime: 1252 ms, faster than 5.01% of Python3 online submissions
Memory Usage: 12.7 MB, less than 100.00% of Python3 online submissions

牛客网在线编程-斐波那契数列的测试结果:

不通过。 您的代码已保存
运行超时:您的程序未能在规定时间内运行结束,请检查是否循环有错或算法复杂度过大。
case通过率为0.00%

总结:毫无疑问这种递归的思路虽然看似简单,但是效率非常低。正如《剑指Offer》反复提及一个对比:与循环相比,递归的思路简单,代码简洁;但是运算效率低。

用我的Mac book Air运行该程序计算F[37]时,大约需要18.5秒——太慢了,我觉得我算基本上都能够算出来了。

2)循环

对啊,如果我自己手算时,我会不会用上述的思路进行“递归”呢?答案:打死我都不会。每一次那么多的递归,嵌套接着嵌套,我非得把自己套进去。

所以,真正手算时,是如何计算的呢?就是直接由前至后一项项迭代下去,也就是说,这基本上是一个O(n)的循环而已,那程序该如何写呢?

def 

LeetCode 给出的运行结果:

Runtime: 24 ms, faster than 88.50% of Python3 online submissions
Memory Usage: 12.8 MB, less than 100.00% of Python3 online submissions

牛客网给出的运行结果:

恭喜你通过本题
运行时间:24ms
占用内存:5728k

所以计算效率一下子提升上去了。同样用我的Mac book Air运行该程序计算F[37]时,大约需要0.0001秒。

3)对比与分析

所以对比下,究竟为何递归会这么慢呢?(参考《剑指offer》P74,面试题10:斐波那契数列)。

3ee7bc0bb0d658204e7076f34a13c393.png
递归下的Fibonacci数列求解(摘自《剑指offer》)

如上图所示,将f(10)按照递归的思路不断分解,形成上图所示不断扩大的树形结构;最终在分解到f(1)和f(2)的环节,然后再”解“嵌套一层层向上返回值。然而在这个过程中,1)随着n的增大,树形变得异常庞大;2)其中存在着大量的重复计算,如上图在不同的嵌套层次中计算多次f(7),n越大重复越多。因此造成了非常低的计算效果。正如《剑指offer》的评价,这是”效率很低的解法,挑剔的面试官不会喜欢“(P75)。

而采用循环的思路,却不存在这么大的计算消耗,其复杂度为

3)”时间复杂度

但不够实用的解法“

在《剑指offer》P76中也给出了一种更高效但是”不够实用“的解法,我尝试能通过实现。

Fibonacci的递推公式可写成如下形式:

因此对

的求解就变成了一个矩阵幂方的问题,幂方问题请参考另一篇有关 Pow(x, n)的内容,如果采用一般的循环方法,其复杂度仍然为
,而采用递归的方式能够将复杂度降低为

算法比较

(整体意思转述于《剑指offer第二版》P77)

  1. 递归思路看似简单,但是隐含的嵌套太多,分支随着
    不断增大而急剧扩大,并且对越低的分支,需要更多的重复计算,效率一般是最低的;
  2. 循环方法,也较容易理解,算法时间复杂度为
    ;
  3. 幂方思路,虽然复杂度为
    ,但由于隐含的时间常数较大(两个
    的矩阵相乘,至少要计算8次乘法和4次加法),很少有软件会采用这种算法,并且不适合面试。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值