两种方法求解Fibonacci数列

两种方法求解Fibonacci数列

Fibonacci数列
定义:
F1 = F2 = 1 and Fn = Fn−1 +Fn−2
例:
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, …

循环迭代

这是最基础的方法,根据Fn = Fn-1 + Fn-2,从F1开始迭代到FN

#include <stdio.h>

int main(void){
    int n; 
    while(EOF!=scanf("%d",&n)){
        int f0 = 0;
        int f1 = 1;
        int fn;
        if(0==n||1==n){
            printf("%d\n",0==n?f0:f1);
            continue;
        }    
       for(int i=1;i<n;++i){
           fn = f0 + f1;
           f0 = f1;
           f1 = fn;
       } 
       printf("%d\n",fn);
    }
    return 0;
}  

矩阵求解(快速幂)

在用矩阵求解Fibonacci前,我们先来看一个相关知识。
如何快速求解A^n次方。
可以用如下公式:
这里写图片描述
根据此公式,可以用递归的方式求解。

int POW(int a, int n)
{
    if( n == 1 )
        return a;
    int result = 1;
    int a1 = POW( a, k/2 );
    a1 = a1*a1;
    if( k & 1 )//奇数
        result = result * a;
    result = result * a1;
    return result;
}

当然一般有递归就有循环的写法
注意到, 25=12(2222)
5的二进制位101,和上面奇偶类似,末尾为1时,result*a, a = a*a
否则,只做a=a*a。第一位必为1,因此最后我们会把a乘回给result,不用担心丢失。

int power(int a,int n)
{
    int result = 1;
    while (n!=0)
    {
        if (n&1)//末位为1
        {
            result*= a;
        }
        a*= a;
        n = n >> 1;//右移
    }
    return result;
}

下面来说用矩阵求解Fibonacci
有如下公式:
这里写图片描述

2维矩阵相乘可以如下表示:
其中,二维矩阵相乘可以如下表示:

void multiply(long long result[], long long factor1[], long long factor2[]) {
    long long temp[] = { 0,0,0,0 };
    temp[0] = (factor1[0] * factor2[0] + factor1[1] * factor2[2])%MOD;
    temp[1] = (factor1[0] * factor2[1] + factor1[1] * factor2[3])%MOD;
    temp[2] = (factor1[2] * factor2[0] + factor1[3] * factor2[2])%MOD;
    temp[3] = (factor1[2] * factor2[1] + factor1[3] * factor2[3])%MOD;
    for (int i = 0; i<4; ++i) {
        result[i] = temp[i];
    }
} 

仿照上面求解A^n次方,最终可得如下代码:

void multiply(long long result[], long long factor1[], long long factor2[]);
const long long MOD = (int)pow(10,9)+7;

int main(void) {
    long long int n;
    while (scanf("%lld", &n) != EOF) {
        if (0 == n || 1 == n || 2 == n) {
            printf("%d\n", 0 == n ? 0 : 1);
            continue;
        }
        long long result[] = { 1,0,1,0 };//单位矩阵
        long long factor[] = { 1,1,1,0 };
        n -= 1;
        while (n) {
            if ((n & 1) == 1) {
                multiply(result, result, factor);
            }
            multiply(factor, factor, factor);
            n >>= 1;
        }
        printf("%lld\n", result[0]);

    }

    return 0;
}

void multiply(long long result[], long long factor1[], long long factor2[]) {
    long long temp[] = { 0,0,0,0 };
    temp[0] = (factor1[0] * factor2[0] + factor1[1] * factor2[2])%MOD;
    temp[1] = (factor1[0] * factor2[1] + factor1[1] * factor2[3])%MOD;
    temp[2] = temp[1];
    temp[3] = (factor1[2] * factor2[1] + factor1[3] * factor2[3])%MOD;
    for (int i = 0; i<4; ++i) {
        result[i] = temp[i];
    }
}     
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值