从斐波那契数列(Fibonacci)入门递归和递推
斐波那契数列,又称黄金分割数列,指的是这样一个数列:0、1、1、2、3、5、8、13、21、……在数学上,斐波纳契数列以如下被以递归的方法定义:F0=0,F1=1,Fn=F(n-1)+F(n-2)(n>=2,n∈N*)在现代物理、准晶体结构、化学等领域,斐波纳契数列都有直接的应用,为此,美国数学会从1960年代起出版了《斐波纳契数列》季刊,专门刊载这方面的研究成果。
上述引用百度百科的概述来说明斐波那契数列的应用广泛之处,废话不多说,直接开始进入下面一个阶段,先明确问题。
nyoj题目连接http://acm.nyist.net/JudgeOnline/problem.php?pid=13
一般同学们一看见题,上来就会写出一段代码
版本一:
#include <stdio.h>
int main() {
int i;
int n;
int a[50]={0,1,1};
scanf("%d",&n);
for(i=3;i<=n;i++)
{
a[i]=a[i-1]+a[i-2];
}
printf("%d",a[n]);
return 0;
}
按此代码,很快就能解出来
可以看见此题数据规模十分小,何谓十分小呢,可能初学者没有那样的概念,输入的n<20说明了此题只会求到f20.
实际上是因为本题的题意是要让用递归写的人也通过,那我们来看看递归要怎么写,
#include <stdio.h>
int f(int n)
{
if(n==0)return 0;
if(n==1||n==2)return 1;
else return f(n-1)+f(n-2);
}
int main() {
int i;
int n;
scanf("%d",&n);
printf("%d",f(n));
return 0;
}
但是正如上文所说,递归速度非常慢经过分析之后可知时间复杂度为o(2^n)可见当n非常大时,程序就跑不出来了!
有没有优化的方法呢
答案是有的,只要加上缓存空间,俗话说空间换时间,
代码如下:
#include <stdio.h>
int buf[100]={1,1};
int f(int n)
{
return buf[n]=((buf[n-1]?buf[n-1]:f(n-1))+(buf[n-2]?buf[n-2]:f(n-2)));
}
int main() {
int i;
int n;
scanf("%d",&n);
printf("%d",f(n));
return 0;
}
这个和上边版本一的效率是一样的,但如果你认为它们俩就是最好的,那就错了!
#include <stdio.h>
int main() {
int i;
int n;
int p=1,q=1,sum=1;
scanf("%d",&n);
for(i=0;i<=n-2;i++)
{
sum=p+q;
p=q;
q=sum;
}
printf("%d",sum);
return 0;
}
这段代码是o(n)时间复杂度,o(3)空间复杂度。比版本一省空间了。
但是这个代码真的是最好的么?答案是错的
最最好的代码是这样的
#include <stdio.h>
int main() {
int n;
scanf("%d",&n);
printf("%.0f",1.0/sqrt(5)*(pow((1+sqrt(5))/2,n)-pow((1-sqrt(5))/2,n)));
return 0;
}
这个版本代码的时间复杂度为o(1),空间复杂度也是o(1)。
少年还需努力啊!!!!!!!!!