斐波那契数列

来源:互联网 发布:建材网络推广 编辑:程序博客网 时间:2024/06/05 04:47

[1]递归法

int Fib(int index)        {            if(index<1)            {                return-1;            }            if(index==1|| index==2)            {                return1;            }            return Fib1(index-1)+Fib1(index-2);        }

[2]递推法

int Fib(int index)        {            if(index<1)            {                return-1;            }             int a1=1,a2=1,a3=1;            for(int i=0;i<index-2;i++)            {                a3=a1+a2;                a1=a2;                a2=a3;            }            return a3;        }

[3]通项公式法

Fibonacci 数列的递推公式是二次递推式,二次递推式的通用解法是转换为如下形式:

转换后的一次递推式很容易生成联合方程,求出通项式,以下是a0=0, a1=1时的 Fibonacci 通项式:

int Fib(int n)        {            double gh5=sqrt((double)5);            return (pow((1+gh5),n)-pow((1-gh5),n))/(pow((double)2,n)*gh5);        }

[4]矩阵快幂法

Fibonacci 数列可以转化为一个等价矩阵,其通项为:

利用乘法的高效性提升性能,一般用于较大的Fibonacci数,因为在int范围内,其性能和代码简洁性不如递推法。

乘法的好处是,如F(90),利用递推,需要90次循环。但利用幂乘,将A^90拆分为A^90=A^64 * A^16 * A^8 * A^2,而A^64、A^16、A^8可以依次由A^2计算得出。只用几次乘法即可达到90次循环递推的效果,n越大,加速性越好。

矩阵乘法的实现代码比较简单,不再给出具体代码。只讨论其中的拆分子步骤。

n的拆分有多种, 甚至无需拆分,直接分割递归也可以。代码如下:

//来自http://www.2cto.com/kf/201208/148361.html

Matrix power1 (LLD p) //矩阵幂 A^k {     Matrix tp = a2 ;     Matrix tr = tmp ;     while (p)     {         if (p&1)           {             tr = Multi (tr, tp) ;             p -- ;             continue ;         }         tp = Multi (tp, tp) ;         p >>= 1 ;     }     return tr ; } Matrix Multi (Matrix a, Matrix b)  //两矩阵相乘 {     Matrix c ;     for (int i = 0; i < 2;i ++)         for (int j = 0; j < 2; j ++)         {             c.mat[i][j] = 0 ;             for (int k = 0; k < 2; k ++)                 c.mat[i][j] += (LLD)a.mat[i][k]*b.mat[k][j] ,c.mat[i][j] %= M ; //矩阵相乘时,需要防止溢出         }     return c ; } 

[5]数的二幂拆分避免递归重复计算

将任意正整数拆分为2的幂的和,如90=2^6+2^4+2^3+2^1.

拆分算法各种各样,下面给出我的二幂拆分法:基于位操作的二幂拆分

这种方法的核心是找到幂指数,下面是找幂指数的代码(核心是分离数的bit位)

typedef struct _x //_x is a tag of type x, generally used in the body for self pointer{ unsigned bits[8*sizeof(unsigned)]; //sizeof  operator returns the number of bytes of type unsigned} x; //define struct xx SplitInt(unsigned value){ x bitArray; //used to store the bit value of n //get each bit from right const unsigned MASK = 1; //MASK = 00000000 00000000 00000000 00000001 for(unsigned i=8*sizeof(unsigned)-1; i>=0; i--) {  bitArray.bits[i] = (value & MASK ? 1 : 0 ); //if value&MASK is 0(false), set the bit to 0;else if it is not 0(true), set the bit to 1;  value >>= 1; //shift value left by 1; } return bitArray;}更一般地,分离数的bit位代码模板如下(核心代码只有一行,即可分离所有位):void func_SplitInt(unsigned value){  for(unsigned i=8*sizeof(unsigned)-1; i>=0; i--,value>>=1)    cout<<(value & 1 ?1:0)<<endl;}

根据《剑指offer》一书中作者提到的方法,书中介绍了一个数学公式如下:



我进行了如下验算:



因此f(n)就等于等式右边的二阶方阵的(n-1)次方所求得方阵的第一行第一列个数的值。代码实现如下:
#include <cstdio>#include <iostream>#include <cstdlib>using namespace std;//求矩阵a的n次幂的函数long long * Matrix(long long *a,int n){    long long *result = (long long *)malloc(sizeof(long long)*4);    long long *finnal = (long long *)malloc(sizeof(long long)*4);    //如果n等于1的话,则直接返回矩阵a,毕竟,一次幂就不必求了。    if(n==1)        return a;    //先求出矩阵的n/2次幂    long long *CurMatrix = Matrix(a,n/2);    //两个矩阵的n/2次幂相乘得到矩阵的n次幂    result[0] = CurMatrix[0]*CurMatrix[0]+CurMatrix[1]*CurMatrix[2];    result[1] = CurMatrix[0]*CurMatrix[1]+CurMatrix[1]*CurMatrix[3];    result[2] = CurMatrix[2]*CurMatrix[0]+CurMatrix[3]*CurMatrix[2];    result[3] = CurMatrix[2]*CurMatrix[1]+CurMatrix[3]*CurMatrix[3];    //如果n为奇数的话,则(n/2)会少一位,补回来。a = a^(n/2)*a^(n/2) * a;    if(n%2==1)    {        finnal[0] = result[0]*a[0]+result[1]*a[2];        finnal[1] = result[0]*a[1]+result[1]*a[3];        finnal[2] = result[2]*a[0]+result[3]*a[2];        finnal[3] = result[2]*a[1]+result[3]*a[3];    }    //如果n为偶数的话,n/2还是n/2    else        finnal = result;    return finnal;}int main(void){    long long a[4];    int n;    cin>>n;    //矩阵按一位数组设置,t[0]即为febonacci(n)    a[0] = 1;    a[1] = 1;    a[2] = 1;    a[3] = 0;    long long *t = Matrix(a,n-1);    cout<<t[0]<<endl;    return 0;}

该算法的复杂度为O(logn)。

0 0
原创粉丝点击