java求数列的最大子段和_递归求斐波那契数列的时间复杂度,不要被网上的答案误导了...

TL;DR:

暴力递归求解斐波那契数列的时间复杂度的紧界不是

,而是

如果你看网上的文章给出的时间复杂度是

,严格来说,这些文章说的并没有错。但如果有人求解出时间复杂度是
,或者
,这不是因为他是错的,而是因为他算出了真正的紧界。

更新一:

由于能力有限,本文中的证明有些复杂。在一些朋友的提示下,我在另一篇文章中写了一些更简洁的证明方法,大家可以看这个证明:

SleepyBag:递归求解斐波那契数列的时间复杂度——几种简洁证明​zhuanlan.zhihu.com

更新二:

评论里有些朋友认为

只是指数的底数不一样,复杂度其实是一样的。这也是算法复杂度分析的常见误区。我在另一篇文章中写到了这个问题,对此有疑惑的朋友可以去看一看:
SleepyBag:二分和三分哪个快?算法复杂度与常数无关?复杂度分析的常见误区​zhuanlan.zhihu.com

今天被某外企的面试官问了使用最暴力的递归方法求解斐波那契数列的时间复杂度。就是下面这个程序的复杂度:

def 

我算出来了,结果他说我算的不对,正确的答案是

。不管我怎么计算证明我的答案他都不相信,好气。

回来上网一搜,发现真的好多人给这个问题下的结论是

。我不能容忍网上流传这种假知识,所以我要自己写篇文章告诉大家,这个问题的答案不是
,或者严格点说,虽然
是对的,但是他不是最紧的界,这个问题还有更小的紧界。
是对的,但
是错的。希望以后不要有人问这种气人的假问题。

斐波那契数列的计算过程很简单。就是简单的

我们把计算

所需的时间记为
。然后记计算加法所需的时间为
,那么显然有

这个数列形式上和斐波那契数列类似。而且与斐波那契数列相比,1 的数量级与

的数量级差的很多,当
较大时几乎可以忽略不计。因此第一眼大致可以推测出这个复杂度应该就是斐波那契数列,即算法的复杂度是
。那么这个结论如何计算呢?可以使用如下思路:

由于递归过程中,每个结点所使用的时间是

的,所以我们需要做的,其实就是数出
的结点到底有多少个。求出递归结点的数量,这个数量,就是复杂度了。

那么,如何求结点数量呢?好了,正文要来了。


我们知道,我们递归过程中所经过的结点只有

种。那么要计算所有结点的个数,只需要计算出每种结点的个数,然后相加就可以了。那么,来吧,我们来计算每种结点各自的个数。

上面所说的结点的个数是这么一个问题:在递归过程中,对于一个数字

,我们计算
计算了几次呢?

我们首先把这个次数记为

其实也可以使用递归的方法计算。

时,对于每个数字
一定是从
中直接递归来的。具体的,每个
会直接递归出一个
,而每个
也会直接递归出一个
。什么?你说间接递归怎么算?不用算,
间接递归出的
其实就是
递归出的
,已经被计算进去了。

因此,可以知道,其实有

。这是什么?这是斐波那契数列!只不过是反过来的。它的初始项是
,因为显然
只被计算了一次。

为了方便大家理解,我画了一张图:

0005e9ab841204431930972bd8f9aa63.png

那么显然,其实就有

。除了一个例外:
会直接返回结果,不会递推到
,因此有
。而我们要计算的是所有结点的数量和的,所以求和的结果是,

所以其实要计算的就是斐波那契数列的通项和。现在我们离答案已经很接近了,那这个通项和如何计算呢?

不需要计算。我们使用二叉树的性质来直接得到它的数量级:

从上面的图中可以看出,斐波那契数列的这颗递归树,每个内部结点都有两个子结点。而这样的二叉树有一个性质:内部结点的数量等于叶子节点的数量减 1. 那么,叶子节点有多少呢?我们知道,这个递归过程到

或者
时会直接终止,因此叶子节点的数量是

那么再加上非叶子结点的数目,可以得到总的结点数目

因此,总的结点数目数量级为

。这就是暴力递归求解斐波那契数列的时间复杂度。

这个数量级也是指数级的,大家在网上可以查到斐波那契数列的通项公式

忽略掉其中的常数系数,以及绝对值永远小于 1 的

,答案是等价于
的。

最后说一句,这件事情真的很气人。有的时候你比面试官厉害也不行。

面试官只知道网上的

的答案,这没有问题,毕竟不是每个人都可以什么都知道。但是我几次尝试证明,他都根本没有在听,而是反复强调
就是正确答案,叫我不要浪费力气。

希望大家以后如果做了面试官,可以放下一些傲慢,承认自己知道的不一定是对的,承认自己面前这个人可能真的知道一些你和你身边的人都不知道的东西。至少可以给他一点时间,认真地去听一听他说的东西,不要固执于自己已知的所谓“正确答案”。而如果你没有能力与人讨论解法的正确性,那就不要自作聪明地出一些你只知道“答案”的“难题”。完。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值