一、递归
一般来说递归实现的代码都是比较整洁的,但效率不高。
递归的逻辑也很简单,代码实现如下:
long long Fibonacci_Solution1(unsigned int n)
{
if(n <= 0) return 0;
if(n == 1) return 1;
return Fibonacci_Solution1(n-1) + Fibonacci_Solution1(n-2);
}
缺点如下:
- 虽然思路清晰,代码简洁,但是在计算的过程中发生了很多次无用的计算,下面的树形结构可以很好的体现:
- 通过此图我们可以发现,在计算F(4)的时候,前面的F(0) F(1)等就不止计算了一次,那么就会造成时间上的浪费:每一次函数的调用,都需要在内存栈中分配空间以保存参数、返回地址以及临时变量,而且往栈里面压入数据和取出数据都是需要时间的。
- 还有一个对于所有的递归都会存在的问题,递归可能会导致调用栈溢出,因为每一次函数的调用都会在栈中分配空间,然而每个栈的空间大小是有限制的。当层级太多的时候,就会造成栈溢出了。比如上面的代码,如果输入小一些的数值,还会输出正确的结果,但是当输入5000这样的比较大的数字的时候,就会报错。
二、循环
- 循环实现的话就解决了上述的问题:
long long Fibonacci_Solution2(unsigned int n)
{
if(n <= 1) return n;
long long fib1 = 1, fib0 = 0, fibN = 0;
for(int i = 2;i <= n;i++)
{
fibN = fib1 + fib0;
fib0 = fib1;
fib1 = fibN;
}
return fibN;
}
所以说,在笔试或面试中遇到了斐波那契,我们要使用循环去解决,不要使用递归,递归中存在很多的隐患。