斐波那契(Fibonacci)数列
来源:互联网 发布:note station windows 编辑:程序博客网 时间:2024/05/06 01:48
以下取自《编程之美-微软技术面试心得》
斐波那契数列由如下递推关系式定义:
F(0)=0 F(1)=1
F(n)=F(n-1)+F(n-2) if n>1
求解斐波那契数列的方法有以下几种:
1.根据递推公式可以很容易想到用递归的方法求解第n+1项的值,代码如下:
int Fibonacci(int n){
if(n<=0)return 0;
else
if(n==1)return 1;
else
return Fibonacci(n-1)+Fibonacci(n-2);
}
这种方法在计算F[n]时,需要计算从F[2]到F[n-1]每一项的值,这样简单的递归式存在着很多的重复计算,如求F[5]=F[4]+F[3],在求F[4]的时候也需要求一次F[3]的大小,等等。
2.为了减少上述的重复运算,可以用一个数组存储所有已经计算过的项。这样便可以达到用空间换时间的目的。在这种情况下,时间复杂度为O(N),而空间复杂度也为O(N)。
int Fibonacci3(int n)
{
int *res = new int[n+1];
res[0]=0;
res[1]=1;
int i=0,result=0;
if(n<=0)
return 0;
if(n==1)
return 1;
for(i=2;i<=n;i++)
{
res[i]=res[i-1]+res[i-2];
}
result=res[n];
delete[] res;
return result;
}
该方法是根据编程之美书中题意实现的,申请了数组,空间复杂度为o(n);
但其实有空间复杂度更小的解法,只保存之前两项的值为x和y,计算待求的z后更新x和y,这样空间复杂度就减少了。代码如下:
int Fibonacci2(int n)
{
int i=0,x=0,y=1,z=0;
if(n<=0)
return 0;
if(n==1)
return 1;
for(i=2;i<=n;i++)
{
z=x+y;
x=y;
y=z;
}
return z;
}
3.如果我们知道一个数列的通项公式,利用公式来计算会更加容易。能不能把这个函数的递推公式计算出来呢?
由递推公式F(n)=F(n-1)+F(n-2),知道F(n)的特性方程为:x^2=x+1(见补充)
有根:x1=(1+sqrt(5.0))/2,x2=(1-sqrt(5.0))/2
所以存在A,B使得:
F(n)=A*x1^n+B*x2^n
代入F(0)=0,F(1)=1,解得A=1/sqrt(5.0),B=-1/sqrt(5.0),即
F(n)=(x1^n-x2^n)/sqrt(5.0)
通过公式,我们可以在O(1)的时间内得到F(n)。但公式引入了无理数,所以不能保证结果的精度。
4.注意到Fibonacci数列是二阶递推数列,所以存在一个2*2的矩阵A,使得:
(F[n] F[n-1])=(F[n-1] F[n-2])*A,结合F[n]=F[n-1]+F[n-2]求解,可得:
A=1 1,1 0(上面是1 1,下面为1 0),由上面的矩阵递推公式有:
(F[n] F[n-1])=(F[n-1] F[n-2])*A=(F[n-2] F[n-3])*A^2=...=(F[1] F[0])*A[n-1],或
剩下的问题就是求解矩阵A的方幂。A^n=A*A*...*A,最直接的解法就是通过n-1次乘法得到结果。但是当n很大时,比如1 000 000或1 000 000 000,这个算法的效率就不能接受了。当然,在这个情况下,F[n]在int所表示的整数里早就溢出了,但如果要求解的是F[n]对某个素数的余数时,这个算法会是非常有用和高效的。
注意到:
A^(x+y)=A^x*A^y
A^(x*2)=A^(x+x)=(A^x)^2
用二进制方法表示n:
n=ak*2^k+a(k-1)*2^(k-1)+...+a1*2+a0(其中ai=0或1,i=0,1,...,k)
A^n=A^(ak*2^k+a(k-1)*2^(k-1)+...+a1*2+a0)=(A^(2^k))^ak*...*A^a0
如果能够得到A^(2^i)的值,就可以再经过logn次乘法得到A^n.
而这容易通过递推得到:
A^(2^i)=(A^(2^(i-1)))^2。根据上面的思想,具体代码如下:
Class Matrix; //假设我们已经有了实现乘法操作的矩阵类
Matrix MatrixPow(const Matrix &m,int n){ //求解m的n次方
Matrix result=Matrix::Identity; //赋初值为单位矩阵
Matrix tmp=m;
for(;n;n>>=1){
if(n&1)result*=tmp;
tmp*=tmp;
}
}
int Fibonacci(int n){
Matrix an=MatrixPow(A,n-1); //A的值就是上面求解出来的
return F1*an(0,0)+F0*an(1,0);
}
整个算法的时间复杂度为O(logn)
解法3其实就是用到数学公式求得的矩阵A,求其n次幂时用了分冶的策略,减少了运算次数
- 斐波那契Fibonacci数列
- 斐波那契 (Fibonacci)数列
- Fibonacci(斐波那契)数列实现
- 斐波那契(Fibonacci)数列
- 斐波那契(Fibonacci)数列
- 斐波那契数列(Fibonacci)
- 斐波那契(Fibonacci)数列
- 斐波那契数列(Fibonacci)
- 斐波那契(Fibonacci)数列
- 斐波那契(Fibonacci)数列
- 斐波那契数列 Fibonacci sequence
- 斐波那契数列-Fibonacci Sequence
- Fibonacci(斐波那契数列)
- 斐波那契数列(fibonacci)
- 斐波那契数列(Fibonacci)
- Fibonacci斐波那契数列序列
- 斐波那契数列Fibonacci
- 斐波那契数列(Fibonacci)
- SQL语法操作全集
- uml
- 异常处理过程
- const的用法
- Arrays_Strings 判断字符串中的字符是否唯一@CareerCup
- 斐波那契(Fibonacci)数列
- linux shell实现随机数多种方法(date,random,uuid)
- 数据库索引应用(ms-sql)
- 物联网中的RPL路由协议(一)----概述
- 限制textbox只能输入数字?
- Latex处理jpg图片(转)
- 框架Struts的action中编写的基于session的购物车逻辑代码
- SQL 左外连接,右外连接,全连接,内连接
- 提高数据库处理查询速度