面试题10:斐波那契数列
【0】目录:
【1】题目
【2】分析
【3】测试代码
【4】测试结果
【5】算法优劣分析
【1】题目:
写一个函数,输入n,求斐波那契(Fibonacci)数列的第n项。
斐波那契数列: 1,1,2,3,5,8,13,21,34,55,89 ……
【2】分析:
在斐波那契数列中,不难得出规律,当n > 2时,某个数等于前两位数之和,如: 2 = 1+ 1;3 = 1+ 2; 5 = 2 +3……
那么我们可以分为三个部分来求解,如下所示:
【3】测试代码:
#include<iostream>
using namespace std;
//========================循环实现===============================
long long Fibonacci01(unsigned int n )
{
int result[2]={0,1};
if (n < 2)
{
return result[n];
}
long long fib1 = 0;
long long fib2 = 1;
long long fibn = 0;
for(int i = 2; i<= n ;++i )
{
fibn = fib1+fib2;
fib1 = fib2;
fib2 =fibn;
}
return fibn;
}
//===========================递归实现================================
long long Fibonacci02(unsigned int n)
{
if(n <= 0)
{
return 0;
}
if(n == 1)
{
return 1;
}
if(n >= 2)
return Fibonacci02( n - 1)+Fibonacci02( n - 2) ;
}
//====================测试代码========================
void test()
{
long long ret1 = 0,ret2 = 0 ;
int n = 0;
printf("请输入待求斐波那契数的数:\n");
scanf( "%d", &n );
ret1 = Fibonacci01( n );
ret2 = Fibonacci02( n );
printf("循环实现第%d个斐波那契数ret1为: %lld\n",n, ret1);
printf("递归实现第%d个斐波那契数ret2为: %lld\n",n, ret2);
}
int main()
{
test();
return 0;
}
【4】测试结果如下:
【5】算法优劣分析:
上面我们采用了循环和递归分别求第n个斐波那契数,那么这两种方式各有优缺点:
递归算法:
递归的本质是将一个难以解决的大问题分解成若干个小的模块,每个小模块再来求解;递归的底层是用栈来实现的;递归用来解决这个问题,显然是合适的;优点:代码量少,逻辑清晰、算法一目了然;缺点:在求斐波那契数列的时候,会大量的重复调用现象,如下图所示,( f ( 6 ) 计算了4次) 这些重复的操作会占用大量的时间,因此,当所求的斐波那契数过大时,效率不高,当输入40时,明显要等几秒,结果才会出来,当数字过大时,将无法计算;另外,在函数调用的时候,会开辟空间,而每个进程的栈容量都是有限的,这就容易造成栈溢出;显然,使用递归算法,那么,算法的时间复杂度O 是以n的指数的方式递增的;
循环算法:
只要递归能实现的地方,基本都可以通过循环实现,循环看似比较繁琐,但实际上,是最实用的一种方案,我们可以将已经得到的中间项保存起来,下次计算的时候,先查找一下,如果之前计算过了,就不再重复计算了,显然这种方法的时间复杂度为O(n)