TL;DR:
暴力递归求解斐波那契数列的时间复杂度的紧界不是
如果你看网上的文章给出的时间复杂度是
更新一:
由于能力有限,本文中的证明有些复杂。在一些朋友的提示下,我在另一篇文章中写了一些更简洁的证明方法,大家可以看这个证明:
SleepyBag:递归求解斐波那契数列的时间复杂度——几种简洁证明zhuanlan.zhihu.com更新二:
评论里有些朋友认为
今天被某外企的面试官问了使用最暴力的递归方法求解斐波那契数列的时间复杂度。就是下面这个程序的复杂度:
def
我算出来了,结果他说我算的不对,正确的答案是
回来上网一搜,发现真的好多人给这个问题下的结论是
斐波那契数列的计算过程很简单。就是简单的
我们把计算
这个数列形式上和斐波那契数列类似。而且与斐波那契数列相比,1 的数量级与
由于递归过程中,每个结点所使用的时间是
那么,如何求结点数量呢?好了,正文要来了。
我们知道,我们递归过程中所经过的结点只有
上面所说的结点的个数是这么一个问题:在递归过程中,对于一个数字
我们首先把这个次数记为
当
因此,可以知道,其实有
为了方便大家理解,我画了一张图:
那么显然,其实就有
所以其实要计算的就是斐波那契数列的通项和。现在我们离答案已经很接近了,那这个通项和如何计算呢?
不需要计算。我们使用二叉树的性质来直接得到它的数量级:
从上面的图中可以看出,斐波那契数列的这颗递归树,每个内部结点都有两个子结点。而这样的二叉树有一个性质:内部结点的数量等于叶子节点的数量减 1. 那么,叶子节点有多少呢?我们知道,这个递归过程到
那么再加上非叶子结点的数目,可以得到总的结点数目
因此,总的结点数目数量级为
这个数量级也是指数级的,大家在网上可以查到斐波那契数列的通项公式
忽略掉其中的常数系数,以及绝对值永远小于 1 的
最后说一句,这件事情真的很气人。有的时候你比面试官厉害也不行。
面试官只知道网上的
希望大家以后如果做了面试官,可以放下一些傲慢,承认自己知道的不一定是对的,承认自己面前这个人可能真的知道一些你和你身边的人都不知道的东西。至少可以给他一点时间,认真地去听一听他说的东西,不要固执于自己已知的所谓“正确答案”。而如果你没有能力与人讨论解法的正确性,那就不要自作聪明地出一些你只知道“答案”的“难题”。完。