斐波那契数列的几种求解方法

斐波那契数列,说起来大家都很熟悉,在练习编程的时候,也会经常被拿来作为例子

递归

这也是最常见的解法了,在最开始学习编程的时候,老师经常用这个例子。
因为他的定义就是递归的,用它可以显而易见地提出递归的思想, n=0n=1 作为递归基,其他的数分别递归求解 fn=fn1+fn2

int fib(int n)
{
    if(n == 0) return 0;
    if(n == 1) return 1;
    return fib(n-1) + fib(n-2);
}

动规

但是很容易地就会发现,这个思路十分清晰的算法太慢了。因为他们中的很多值在被重复地计算,例如 f5=f4+f3 , f4=f3+f2 f3 就被重复地计算了,重复的部分增加的非常快,一旦当 n 大于 40 多时,就已经很难进行计算了。

这里我们可以利用动规的思想来进行计算,复杂度都能降到 O(n)

记忆化

也是最简单的,可以先开一个数组,并且在每次计算出结果后,保存下来,就可以避免重复计算。

int f[10000];
int fib(int n)
{
    if(f[n]) return f[n];

    if(n == 0) return f[0] = 0;
    if(n == 0) return f[1] = 1;
    return f[n] = fib(n-1) + fib(n-2);
}

递推

从上面的定义方程就可以看出来,每一个值只与前面的数有关于后面的数无关,这样就可以从前往后依次计算(问题比较简单,想法太顺理成章了,动规得太不明显了,但的确是动规)

int fib(int n)
{
    int f[3] = { 0, 1, 1}
    if(n<=2) return f[n];
    for(int i=3; i<=n; i++)
    {
        f[0] = f[1];
        f[1] = f[2];
        f[2] = f[1] + f[0];
    }
    return f[2];
}

当然平时做题时还是会开一个数组进行保存,以后查询时就是 O(1) 的复杂度了。

int f[10000];
int init()
{
    f[0] = 0;
    f[1] = 1;
    for(int i=2; i<10000; i++) f[i] = f[i-1] + f[i-2];
}
int fib(int n)
{
    return f[n];
}

快速幂

上面的算法,已经达到了 O(n) 的复杂度,已经是非常优秀的了,但是当我们需要求解很大的答案是,例如 1000000000 之类,那么也是很耗费时间的,或者说我们需要查询的次数比较少,比较分散,那么我们浪费的空间就比较大。下面利用矩阵就是另外一种求解的方法。
利用矩阵的性质我们可以得到下面的结论

(fn+1fnfnfn1)(1110)=(fn+1+fnfn+fn1fn+1fn)fib=(fn+2fn+1fn+1fn)

而我们令 n=1, 则

(fn+1fnfnfn1)=(1110)

综上,我们可以得出这样的结论
(fn+1fnfnfn1)=(1110)n

理论有了,我们就可以类推数的快速幂来计算矩阵的快速幂。

// 数的快速幂
int quick_pow(int a, int n)
{
    int re = 1;
    int base = a;
    while(n)
    {
        if(n&1) re *= base;
        base *= base;
        n >>= 1;
    }
    return n;
}

矩阵快速幂,需要自己写矩阵的乘法,然后直接套用数的快速幂的模板就行

// 矩阵快速幂

struct matrix
{
    int data[2][2];
    // 矩阵乘法
    matrix operator*(matrix & rhs)
    {
        matrix temp;
        for(int i=0; i<2; i++)
        {
            for(int j=0; j<2; j++)
                temp.data[i][j] = ( data[i][0]*rhs.data[0][j] 
                                  + data[i][1]*rhs.data[1][j]) % mod;
        }
        return temp;
    }
};

int solve(int n)
{
    // 初始化为单位矩阵
    matrix re;
    for(int i=0; i<2; i++)
        for(int j=0; j<2; j++) re.data[i][j] = (i==j);
    matrix base;
    for(int i=0; i<2; i++)
        for(int j=0; j<2; j++) base.data[i][j] = 1;
    base.data[1][1] = 0;

    // 数的快速幂核心代码
    while(n)
    {
        if(n&1) re = re * base;
        base = base * base;
        n >>= 1;
    }
    return re.data[0][1];
}

例题:poj3070 - Fibonacci 解题报告

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值