您好、欢迎来到现金彩票网!
当前位置:在线斗牛棋牌游戏 > 尾递归 >

求职干货:再也不怕面试官问斐波那契数列了!

发布时间:2019-06-07 21:26 来源:未知 编辑:admin

  假如面试官让你编写求斐波那契数列的代码时,是不是心中暗喜?不就是递归么,早就会了。如果真这么想,那就危险了。

  我们仔细分析我们的递归算法,就会发现问题,当我们计算fibo(5)的时候,是下面这样的:

  最终为了得到fibo(5)的结果,fibo(0)被计算了3次,fibo(1)被计算了5次,fibo(2)被计算了2次。可以看到,它的计算次数几乎是指数级的!

  因此,虽然递归算法简洁,但是在这个问题中,它的时间复杂度却是难以接受的。

  除此之外,递归函数调用的越来越深,它们在不断入栈却迟迟不出栈,空间需求越来越大,虽然访问速度高,但大小是有限的,最终可能导致栈溢出。

  一般来说,8M的栈空间对于一般程序完全足够。如果8M的栈空间不够使用,那么就需要重新审视你的代码设计了。

  既然我们知道最初版本的递归存在大量的重复计算,那么我们完全可以考虑将已经计算的值保存起来,从而避免重复计算,该版本代码实现如下:

  但是特别注意的是,这种改进版的递归,虽然避免了重复计算,但是调用链仍然比较长。

  既然递归法不够优雅,我们换一种方法。如果不用计算机计算,让你去算第n个斐波那契数,你会怎么做呢?

  我想最简单直接的方法应该是:知道第一个和第二个后,计算第三个;知道第二个和第三个后,计算第四个,以此类推。

  最终可以得到我们需要的结果。这种思路,没有冗余的计算。基于这个思路,我们的C语言实现如下:

  可以看到,计算第50个斐波那契数只需要0.002s!时间复杂度为O(n)。

  要计算第n个斐波那契数,我们可以先计算第一个,第二个,如果未达到n,则继续递归计算,尾递归C语言实现如下:

  可见,其效率并不逊于迭代法。尾递归在函数返回之前的最后一个操作仍然是递归调用。

  尾递归的好处是,进入下一个函数之前,已经获得了当前函数的结果,因此不需要保留当前函数的环境,内存占用自然也是比最开始提到的递归要小。时间复杂度为O(n)。‍

  如果a为矩阵,等式同样成立,后面我们会用到它。假设有矩阵2*2矩阵A,满足下面的等式:

  /*计算2*2矩阵乘法,这里没有写成通用形式,有兴趣的可以自己实现通用矩阵乘法*/

  该算法的关键部分在于对A^n的计算,它利用了我们开始提到的等式,对奇数和偶数分别处理。

  关于通项公式的求解,可以当成一道高考数列大题,有兴趣的可以尝试一下(提示:两次构造等比数列)。C语言代码实现如下:

  如果需要求解的斐波那契数列的第n个在有限范围内,那么完全可以将已知的斐波那契数列存储起来,在需要的时候读取即可,时间复杂度可以为O(1)。

  关于斐波那契数列在实际中很常见,数学上也有很多奇特的性质,有兴趣的可在百科中查看。

  可以看到,对于求斐波那契数列的问题,使用一般的递归并不是一种很好的解法。

  所以,当你使用递归方式实现一个功能之前,考虑一下使用递归带来的好处是否抵得上它的代价。

  作者简介:守望,一名好文学,好技术的开发者。在个人公众号【编程珠玑】分享原创技术文章和学习资源,期待一起交流学习。

http://missartypants.com/weidigui/66.html
锟斤拷锟斤拷锟斤拷QQ微锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷微锟斤拷
关于我们|联系我们|版权声明|网站地图|
Copyright © 2002-2019 现金彩票 版权所有