Leetcode-劍指offer-斐波那契數列-矩陣快速冪實現

前情

本文內容首先需要了解快速冪的實現原理,詳情見 pow(x, n)快速冪實現

題目

leetcode鏈接: https://leetcode-cn.com/problems/fei-bo-na-qi-shu-lie-lcof/

題目描述:

寫一個函數,輸入 n ,求斐波那契(Fibonacci)數列的第 n 項。斐波那契數列的定義如下:

F(0) = 0,   F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契數列由 0 和 1 開始,之後的斐波那契數就是由之前的兩數相加而得出。

答案需要取模 1e9+7(1000000007),如計算初始結果爲:1000000008,請返回 1。

 

示例 1:

輸入:n = 2
輸出:1
示例 2:

輸入:n = 5
輸出:5
 

提示:

0 <= n <= 100

解法

樸素的解法就不寫了,小學生都會TAT , 這裏給出矩陣快速冪的解法

首先給出斐波那契數列定義

\\ $\cdot F(0)=0$ \\ $\cdot F(1)=1$ \\ $\cdot F(n)=F(n-1)+F(n-2)(n>=2)$
$\cdot F(n)=F(n-1)+F(n-2)(n>=2)$ 用矩陣表示則有 

$$ \left[\begin{array}{c} F(n)=F(n-1)+F(n-2) \\ F(n-1) \end{array}\right]=\left[\begin{array}{ll} 1 & 1 \\ 1 & 0 \end{array}\right] \times\left[\begin{array}{c} F(n-1) \\ F(n-2) \end{array}\right] $$

F(n-1), F(n-2) 有着同樣的表示方法,則遞推得到

$$ \left[\begin{array}{c} F(n) \\ F(n-1) \end{array}\right]=\left[\begin{array}{ll} 1 & 1 \\ 1 & 0 \end{array}\right] \times\left[\begin{array}{c} F(n-1) \\ F(n-2) \end{array}\right]=\left[\begin{array}{cc} 1 & 1 \\ 1 & 0 \end{array}\right]^{2} \times\left[\begin{array}{c} F(n-2) \\ F(n-3) \end{array}\right]=\ldots=\left[\begin{array}{cc} 1 & 1 \\ 1 & 0 \end{array}\right]^{n-1} \times\left[\begin{array}{c} F(1) \\ F(0) \end{array}\right] $$

而 \left[\begin{array}{cc} 1 & 1 \\ 1 & 0 \end{array}\right]^{n-1}可以用矩陣快速冪算出來,這裏不再贅述矩陣乘法以及快速冪了, 則我們可以用 O(log(n)))的時間計算出來F(n),注意這裏我們將2階矩陣的乘法當作常數纔可以得到這個結論。

代碼

class Solution {
public:
    const long long mod = 1000000007;
    vector<vector<int>> mat_mul(vector<vector<int>> a, vector<vector<int>> b)
    {
        int ra = a.size(), ca = a[0].size(), rb = b.size(), cb = b[0].size();
        vector<vector<int> > res(ra, vector<int>(cb, 0)); 
        for (int k=0; k<ca; k++)
        for (int i=0; i<ra; i++)
        for (int j=0; j<cb; j++)
        {
            res[i][j] += ((a[i][k]%mod)*(b[k][j]%mod))%mod;
        }
        return res;
    }

    vector<vector<int>> quick_mat_pow(vector<vector<int>> a, int n)
    {
        vector<vector<int>> res = {{1, 0},{0, 1}};
        vector<vector<int>> p = a;
        int t = n;
        for (; t>0; t>>=1)
        {
            if (t&1) res = mat_mul(res, p);
            p = mat_mul(p, p);
        }
        return res;
    }

    int fib(int n) {
        vector<vector<int>> f = {{1}, {0}};
        if (n<2) {
           if (n==0) return 0;
           else return 1;
        }
        vector<vector<int>> base = {{1,1},{1,0}};
        return mat_mul(quick_mat_pow(base, n-1), f)[0][0];
    }
};

最後想說;

我的源碼都整理在了github上,劍指offer專題會分類整理(如樹專題,DP專題,模擬專題,搜索專題等),github鏈接見下文,如果對您有幫助,請幫忙在github中star,這對我很重要!!!! 拜託拜託~!!

github鏈接: https://github.com/wjlpku/Leetcode-interview
 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章