算法提升(5):斐波那契数列套路O(logN)优化

适用问题

题目的本质是类似于求斐波那契数列第N项的值或者需要这样一个过程的问题

满足条件

所求的第N项满足下面这样的严格递推式
F(N) = a * F(N - 1) + b * F(N - 2) + c * F(N - 3) + . . . . . . + x * F(N - y)

优化原理

  1. 首先根据线性代数的知识我们可以得到这样一个关系式(下面画横线的表示也是矩阵)
  2. 将F(y+1)开始一直到F(N)为止的式子写出来,然后前面的式子代入到后面式子,可以得到以下结果
  3. 那么现在的问题就是如何求得这个y阶矩阵,以及如何快速求出矩阵的某次幂。

如何求得这个y阶矩阵

这个矩阵一共有y2个未知数,其实就是求y2元一次方程的解,因为我们可以根据递推公式轻易地求出前面某些项的值,代入即可求出这个y阶矩阵。这里求解的过程是在草稿纸上进行的,不必写在代码里,因为每一题都有特定的y阶矩阵,且每一题中是固定的,自己手动求出直接用即可。

如何快速求出矩阵的某次幂

这里用到了矩阵的快速幂,将幂转换成2进制数,准备一个单位矩阵(相当于十进制的1)和矩阵的1次方,从二进制数的最右边开始,如果这一位是1,则把当前矩阵累乘到单位矩阵上,然后当前矩阵累乘自己,二进制数右移一位;如果是0则单位矩阵不累乘当前矩阵,当前矩阵累乘自己,二进制数右移一位。直到右移到0。这样的求法是O(logN)级别的,因为除了求出y阶矩阵的N-y次幂,其他操作都是O(1)水平的,所以就把整个算法的时间复杂度降低到了O(logN)。这就是斐波那契数列套路

应用案例

求斐波那契数列的第N项值。

    int fib(int n) {
        if(n == 0)
        {
            return 0;
        }
        else if(n == 1 || n == 2)
        {
            return 1;
        }
        int MOD = 1000000007;
        vector<vector<int>> matrix = {{1, 1}, {1, 0}};   //已经提前求好的y阶矩阵
        matrix = pow(matrix, n - 2);
        return (matrix[0][0] + matrix[1][0]) % MOD;
    }
    vector<vector<int>> pow(vector<vector<int>> matrix, int n)   //快速幂
    {
        vector<vector<int>> ans(matrix.size(), vector<int>(matrix[0].size()));
        for(int i = 0; i < ans.size(); i++)
        {
            ans[i][i] = 1;
        }
        while(n != 0)
        {
            if(n & 1)
            {
                ans = mutilMatrix(ans, matrix);
            }
            matrix = mutilMatrix(matrix, matrix);
            n = n >> 1;
        }
        return ans;
    }

    vector<vector<int>> mutilMatrix(vector<vector<int>>& matrix1, vector<vector<int>>& matrix2)  //矩阵乘法
    {
        int MOD = 1000000007;
        vector<vector<int>> ans(matrix1.size(), vector<int>(matrix2[0].size()));
        for(int i = 0; i < ans.size(); i++)
        {
            for(int j = 0; j < ans[0].size(); j++)
            {
                ans[i][j] += (int)(((long)matrix1[i][0] * matrix2[0][j] + (long)matrix1[i][1] * matrix2[1][j])%MOD);
            }
        }
        return ans;
    }
posted @ 2022-08-12 13:16  小肉包i  阅读(67)  评论(0)    收藏  举报