当前位置:   article > 正文

C++求解斐波那契数列的若干方法_斐波那契数列c++

斐波那契数列c++

问题链接:https://www.acwing.com/problem/content/description/207/

问题描述

在这里插入图片描述

方法一:递归

对于斐波那契数来说,每一项都等于他的前两项之和,他的第 0 0 0项和第 1 1 1项分别为 0 , 1 0,1 0,1,那么因为有重复的地方,所有可以使用递归来进行求解

#include <iostream>
using namespace std;

int f_final(int n) {
    if(n < 2) return n;
    return f_final(n-1) + f_final(n-2);
}

int main() {
    int n;
    cin >> n;
    cout << f_final(n) << endl;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

递归计算的节点个数是 O ( 2 n ) O(2^n) O(2n)的级别的,存在大量重复计算。
时间复杂度是 O ( 2 n ) O(2^n) O(2n),一秒内大约能算到第四十项左右。
在这里插入图片描述

重复计算的原因

每一个递归的程序,都可以绘制一棵树,以表示他的执行过程
在这里插入图片描述
由此可以发现,递归的过程中,因为没有记忆话的能力,所有他做了很多的无用功,大量的重复计算,可以使用记忆化进行优化

方法二:记忆化搜索

可以开辟一个数组用于记录计算过的值,下一次再被搜索到的时候,就可以直接得到结果,而不需要继续递归调用了

#include <iostream>
using namespace std;

const int N = 1e6 + 10, mod = 1e9 + 7;
int f[N];

int f_final(int n) {
    if(f[n]) return f[n];
    if(n < 2) return f[n] = n;
    return f[n] = (f_final(n-1) + f_final(n-2)) % mod;
}

int main() {
    int n;
    cin >> n;
    cout << f_final(n) << endl;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

总共有 n n n 个状态,计算每个状态的复杂度是 O ( 1 ) O(1) O(1),所以时间复杂度是 O ( n ) O(n) O(n)

一秒内可以算 n = 1 0 7 n=10^7 n=107 ,但由于是递归计算,递归层数太多会爆栈,大约只能算到 n = 1 0 5 n=10^5 n=105 级别

方法三:非递归

#include <iostream>
using namespace std;

const int N = 1e6 + 10, mod = 1e9 + 7;
int f[N];

int f_final(int n) {
    f[1] = 1;
    for(int i = 2; i <= n; i++) 
        f[i] = (f[i-1] + f[i-2]) % mod;
    return f[n];
}

int main() {
    int n;
    cin >> n;
    cout << f_final(n) << endl;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

总共计算 n n n 个状态,所以时间复杂度是 O ( n ) O(n) O(n)
但是他的瓶颈在于空间复杂度,需要开一个长度是 n n n 的数组,当 n = 1 0 8 n=10^8 n=108 时,需要的内存是 4 × 1 0 8 1024 × 1024 ≈ 381 M B \frac{4\times10^8}{1024\times1024}\approx381MB 1024×10244×108381MB,很容易超内存

方法四:递推 + 滚动变量

从上面递推的过程中,可以发现,对于每一个状态,他只与前面两个状态有关,所有就可以对空间进行一次优化,我们不需要一直报存前面的每一个状态的结果

#include <iostream>
using namespace std;

const int mod = 1e9 + 7;


int f_final(int n) {
    if(n < 2) return n;
    int a = 0, b = 1, c;
    for(int i = 2; i <= n; i++) {
        c = (a + b) % mod;
        a = b;
        b = c;
    }
        
    return c;
}

int main() {
    int n;
    cin >> n;
    cout << f_final(n) << endl;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

时间复杂度还是 O ( n ) O(n) O(n),空间复杂度变成了 O ( 1 ) O(1) O(1)

方法五:快速幂 + 矩阵乘法

在这里插入图片描述

本题中,他的数据范围非常的大,上面的方法都会超时的,必须加以优化

对于斐波那契数列中,相邻的两项 f n f_n fn f n − 1 f_{n-1} fn1,可以进行如下变化:
{ f n f n − 1 } \left\{

fnfn1
\right\} {fnfn1}
⇒ { f n − 1 + f n − 2 f n − 1 } \Rightarrow \left\{
fn1+fn2fn1
\right\}
{fn1+fn2fn1}

⇒ { 1 × f n − 1 + 1 × f n − 2 1 × f n − 1 + 0 × f n − 2 } \Rightarrow \left\{
1×fn1+1×fn21×fn1+0×fn2
\right\}
{1×fn1+1×fn21×fn1+0×fn2}

⇒ { 1 1 1 0 } × { f n − 1 f n − 2 } \Rightarrow \left\{
1110
\right\} \times \left\{
fn1fn2
\right\}
{1110}×{fn1fn2}

所以说,想要计算第 n n n项,可以推导出这样一个公式
{ 1 1 1 0 } n − 1 × { f 1 f 0 } \left\{

1110
\right\}^{n-1} \times \left\{
f1f0
\right\} {1110}n1×{f1f0}
⇒ { 1 1 1 0 } n − 1 × { 1 0 } \Rightarrow \left\{
1110
\right\}^{n-1} \times \left\{
10
\right\}
{1110}n1×{10}

程序

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

typedef long long LL;
const int MOD = 10000;

// 二维矩阵连乘
void Mul(int a[][2],int b[][2],int c[][2]) {
    int t[][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++)
                t[i][j] = (t[i][j] + a[i][k] * b[k][j]) % MOD;
    
    memcpy(c,t,sizeof t);
}

int f_final(int n) {
    if(n < 2) return n;
    
    int res[][2]    = { {1,0},{0,1} };      // 1
    int t[][2]      = { {1,1},{1,0} };      
    int k = n - 1;
    while(k > 0) {
        if(k & 1) Mul(res,t,res);
        Mul(t,t,t);
        k >>= 1;
    }
    
    int x[] = {1,0};
    int c[] = {0,0};
    for(int i = 0; i < 2; i++)
        for(int j = 0; j < 2; j++)
            c[i] = (c[i] + x[j] * res[j][i]) % MOD;
    return c[0];
}

int main() {
    int n;
    while(cin >> n , n != -1) {
        cout << f_final(n) << endl;
    }
    return 0;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/434151
推荐阅读
相关标签
  

闽ICP备14008679号