zoukankan      html  css  js  c++  java
  • Fibonacci Sequence

    递归

    斐波那契数列定义:

    \[F(n)=\left\{\begin{matrix}0, n=0\\ 1, n=1\\ F(n-1)+F(n-2), n>1\end{matrix}\right. \]

    递归解法最直观,但是复杂度也最高:\(O(2^n)\)

    int Fibonacci(int n)
    {
        if (n <= 0) //细节可以处理非法输入
            return 0;
        else if (1 == n)
            return 1;
        return Fibonacci(n - 1) + Fibonacci(n - 2);
    }
    

    为了避免重复计算,可以将每一步计算得到的\(F(i)\)存起来,这样的话时间复杂度降为\(O(n)\),但空间复杂度升为\(O(n)\)

    通项

    求解通项的方法有好几种,下面展示一种用线性代数求解的方法:
    斐波那契数列的递推公式是二阶差分方程,先用一点小技巧将其化为一阶:

    \[\begin{cases}F_{k+2}=F_{k+1}+F_{k}\text{}\\F_{k+1}=F_{k+1}\text{}\\\end{cases} \]

    我们令\(u_k=\begin{bmatrix}F_{k+1}\\F_{k}\\\end{bmatrix}\),那么\(u_{k+1}=\begin{bmatrix}F_{k+2}\\F_{k+1}\\\end{bmatrix}=\begin{bmatrix}1\ 1\\1\ 0\\\end{bmatrix}u_k\)
    矩阵\(A=\begin{bmatrix} 1\ 1\\1\ 0\\\end{bmatrix}\),令\(det(A-\lambda I)=\lambda^2-\lambda-1=0\),求得\(\lambda=\frac{1\pm \sqrt5}{2}\),对应于两个特征值的特征向量为\(x_1=\begin{bmatrix} \lambda_1\\ 1\\ \end{bmatrix},x_2=\begin{bmatrix} \lambda_2\\ 1\\ \end{bmatrix}\)
    求得特征值和特征向量后,我们将\(u_0=\begin{bmatrix} F_1\\ F_0\\ \end{bmatrix}=\begin{bmatrix} 1\\ 0\\ \end{bmatrix}=c_1x_1+c_2x_2\),解得\(c_1=-\frac{1}{\sqrt5}, c_2=\frac{1}{\sqrt5}\)

    \(u_k=S\Lambda^{k}c=\begin{bmatrix} c_1\lambda_1^{k+1}+c_2\lambda_2^{k+1}\\c_1\lambda_1^{k}+c_2\lambda_2^{k}\\\end{bmatrix}\)
    所以通项公式可以表示为\(F(n)=C_1\lambda_1^n+C_2\lambda_2^n\)
    故斐波那契数列的通项公式为:\(F(n)=\frac{1}{\sqrt5}[(\frac{1+\sqrt5}{2})^n-(\frac{1-\sqrt5}{2})^n]\)
    用公式求解的复杂度为\(O(1)\),但是由于无理数在计算机中的存储不是精确的,所以结果的精度很难保证。

    分治

    通过矩阵形式的递推:

    \[\begin{bmatrix}F(n)\\ F(n-1)\end{bmatrix}=\begin{bmatrix}1\ 1\\ 1\ 0\end{bmatrix}\begin{bmatrix}F(n-1)\\ F(n-2)\end{bmatrix} \]

    不断向下递推,可以得到:

    \[\begin{bmatrix}F(n)\\ F(n-1)\end{bmatrix}={\begin{bmatrix}1\ 1\\ 1\ 0\end{bmatrix}}^{n-1}\begin{bmatrix}F(1)\\ F(0)\end{bmatrix} \]

    接下来就是求解矩阵的高次方,通过快速幂可以在\(O(logn)\)时间内进行计算:
    整数的快速幂代码:

    int QuickPow(int a,int n)
    {
        int ans = 1;
        while (n)
        {
            if (n & 1)
                ans *= a;
            a *= a;
            n >>= 1;
        }
    
        return ans;
    }
    
    // 递归版本
    int raise(int base, int exp) {
        if (exp == 0)
            return 1;
        int half = raise(base, exp / 2);
        if (exp % 2)
            return base * half * half;
        else
            return half * half;
    }
    

    将传入的参数改为矩阵,乘法改为矩阵乘法,就可以得到矩阵快速幂:
    以二阶矩阵为例,求解斐波那契数列:

    #define _CRT_SECURE_NO_WARNINGS
    
    #include <iostream>
    
    using namespace std;
    
    struct Matrix {
        int a[2][2];
    }base,ans;
    
    Matrix multi(Matrix a, Matrix b)
    {
        Matrix res;
        for (int i = 0; i < 2; i++) //第i行
        {
            for (int j = 0; j < 2; j++)  //第j列
            {
                res.a[i][j] = 0;
                for (int k = 0; k < 2; k++)
                    res.a[i][j] += a.a[i][k] * b.a[k][j];
            }
        }
    
        return res;
    }
    
    Matrix QuickPow(int n)
    {
        base.a[0][0] = base.a[0][1] = base.a[1][0] = 1;
        base.a[1][1] = 0;   //初始化矩阵
    
        //结果矩阵初始化为单位阵
        ans.a[0][0] = ans.a[1][1] = 1;
        ans.a[1][0] = ans.a[0][1] = 0;
    
        while (n)
        {
            if (n & 1)
            {
                ans = multi(ans, base);
            }
            base = multi(base, base);
            n >>= 1;
        }
    
        return ans;
    }
    
    int main()
    {
        int n;
        cin >> n;
    
        QuickPow(n);
        cout << ans.a[1][0] << endl;
    
        return 0;
    }
    

    动态规划

    int Fibonacci(int n) {
        int a = 0, b = 1;
        int ans = 0;
        for(int i = 0;i < n;++i) {
            ans = a + b;
            a = b;
            b = ans;
        }
        return ans;
    }
    

    Refs

    斐波那契数列

  • 相关阅读:
    rem是如何实现自适应中的?
    meta基础知识
    JqueryMobile动态生成listView并实现刷新的两种方法
    javascript中for/in循环及使用技巧
    JavaScript中this详解
    使用css实现全兼容tooltip提示框
    如何使用CSS3画出一个叮当猫
    jQuery实现的Div窗口震动效果实例
    jQuery实现动态添加和删除一个div
    js对文章内容进行分页示例代码
  • 原文地址:https://www.cnblogs.com/EIMadrigal/p/11478906.html
Copyright © 2011-2022 走看看