【转】求斐波那契数列的若干种方法

转自:https://www.acwing.com/blog/content/25/
作者:yxc


斐波那契问题定义

定义 a 0 = 1 a 1 = 1 , a n = a n 1 + a n 2 a n 是多少。
为了避免考虑整数溢出问题,我们求 a n %p的值, p = 10 9 + 7

算法1 直接递归

递归计算的节点个数是 O ( 2 n ) 级别的,存在大量重复计算,递归层数太多会爆栈。

const int MOD=1000000007;

int Fibonacci(int n)
{
if(n<=1) return 1;
return (f(n-1)+f(n-2))%MOD;
}

算法2 记忆化搜索

(i)用一个大数组记录中间结果

如果已经计算过就直接查表,否则再递归计算,总共要计算n个状态,复杂度为 O ( n )

const int MOD=1000000007;
int a[100000];
int Fibonacci(int n)
{
if(n<=1) return 1;
if(a[n]) return a[n];
return (f(n-1)+f(n-2))%MOD;
}
(ii)用数组中保存的值循环计算
const int MOD=1000000007;
int a[10000000];
int Fibonacci(int n)
{
    a[0]=a[1]=1;
    for(int i=2;i<=n;i++)
    {
        a[i] = a[i - 1] + a[i - 2];
        a[i] %= MOD;
    }
}
(iii)滚动变量
const int MOD = 1000000007;
int f4(int n)
{
    int x, y, z;
    x = y = 1;
    for (int i = 2; i <= n; i ++ )
    {
        z = (x + y) % MOD;
        x = y;
        y = z;
    }
    return z;
}

快速幂算法

快速幂算法旨在计算 a b 时通过用二进制拆分b减少计算量。

如b=11时,11的二进制表示为1011,可以将11拆分为 2 3 + 2 1 + 2 0 ,从而将计算转化为 a 8 + a 2 + a 1 ,使复杂度降至 O ( l o g b )

快速幂算法的代码:

int qmi(int m, int k, int p)
{
    int res = 1, t = m;
    while (k)
    {
        if (k&1) res = res * t % p;//检查二进制该位是否为1
        t = t * t % p;//累乘t以备使用
        k >>= 1;
    }
    return res;
}

利用这个矩阵的n次方来计算累加,此处用矩阵的快速幂算法

[ 1 1 1 0 ]  

void mul(int a[][2], int b[][2], int result[][2])
{
    int temp[][2] = {{0, 0}, {0, 0}};
    for (int i = 0; i < 2; i ++ )
        for (int j = 0; j < 2; j ++ )
            for (int k = 0; k < 2; k ++ )
            {
                long long x = temp[i][j] + (long long)a[i][k] * b[k][j];
                temp[i][j] = x % MOD;
            }
    for (int i = 0; i < 2; i ++ )
        for (int j = 0; j < 2; j ++ )
            result[i][j] = temp[i][j];
}


int f_final(long long n)
{
    int x[2] = {1, 1};

    int a[2][2] = {{1, 1}, {1, 0}};

    int res[][2] = {{1, 0}, {0, 1}};
    int t[][2] = {{1, 1}, {1, 0}};
    long long k = n - 1;
    while (k)
    {
        if (k&1) mul(res, t, res);
        mul(t, t, t);
        k >>= 1;
    }

    int c[2] = {0, 0};
    for (int i = 0; i < 2; i ++ )
        for (int j = 0; j < 2; j ++ )
        {
            long long r = c[i] + (long long)x[j] * res[i][j];
            c[i] = r % MOD;
        }

    return c[0];
}


int main()
{
    long long n ;

    cin >> n;
    cout << f_final(n) << endl;

    return 0;
}

这里写图片描述
今天过的开不开心呀?

猜你喜欢

转载自blog.csdn.net/qq_24634505/article/details/80697936
今日推荐