斐波那契数列

[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 x
x 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值