求解斐波那契數列復雜度分析


前言:斐波那契作為一個算法基礎知識,大家一定要掌握,祝大家學得開心~

什么是斐波那契數列(Fibonacci sequence)?

斐波那契數列(Fibonacci sequence),又稱黃金分割數列、因數學家列昂納多·斐波那契(Leonardoda Fibonacci)以兔子繁殖為例子而引入,故又稱為“兔子數列”,指的是這樣一個數列:1、1、2、3、5、8、13、21、34、……在數學上,斐波納契數列以如下被以遞歸的方法定義:F(0)=0,F(1)=1, F(n)=F(n-1)+F(n-2)(n>=2,n∈N*)。

方式一:遞歸

F(n)=F(n-1)+F(n-2),利用遞歸思想,每次計算當前的值時候,就要引用之前的兩個值,一步一步的遞歸,一直到最起始處,直至F(1)和F(2)。

遞歸算法程序:

long long Fib1(long long n)
{
    assert(n >= 0);
    //遞歸
    return n < 2 ? n : (Fib1(n - 1) + Fib1(n - 2));
}
View Code

遞歸算法中有大量的重復計算,效率低下,當需要計算的數稍大一點,就需要很長的計算時間,甚至可能導致棧溢出,但優點是代碼簡單,容易理解。

遞歸的深度*每次遞歸所需的輔助空間的個數 ,所以空間復雜度是:O(N)。

遞歸算法時間復雜度為:O(2^(N/2)) <= T(N) <= O(2^N)。計算過程有些復雜,需要利用線性代數知識(紅衣教主出沒~)。

明顯,設T(n)為參數為n時的時間復雜度,則T(n)=T(n-1)+T(n-2) 。

這是數學上的二階常系數差分方程,並且為齊次方程。 特征方程為:x^2-x-1=0 。解得 x=(1±√5)/2 。

 

方式二:非遞歸

1.創建一個數組,每次將前兩個數相加后直接賦給后一個數。這樣的話,有N個數就創建一個包含N個數的一維數組,所以空間復雜度為O(N);由於只需從頭向尾遍歷一邊,時間復雜度為O(N)。在多次查詢斐波那契數可以先初始化就求出數組,這樣查詢時間復雜度就是O(1)了。

long long* Fib2(long long n)
{
    assert(n >= 0);
    //非遞歸
    long long* F = new long long[n + 1];
    F[0] = 0;
    F[1] = 1;
    for (int i = 2; i <= n; i++)
        F[i] = F[i - 1] + F[i - 2];
    
    return F;
}
View Code

2.借助兩個變量first和second,每次將first和second相加后賦給third,再將second賦給first,third賦給second,時間復雜度為O(N),空間復雜度為O(1)。只用於求單個斐波那契數,題目中一般不這么寫,查詢復雜度為O(N)。

long long Fib3(long long n)
{
    assert(n >= 0);
        
    long long first = 0;
    long long second = 1;
        if(n < 2) return n;
        
    long long third;
    for(int i = 2; i <= n; i++)
    {
        third = first + second;
        first = second;
        second = third;
    }
    return third;
}
View Code

計算過程:一般情況下,對步進循環語句只需考慮循環體中語句的執行次數,忽略該語句中步長加1、終值判別、控制轉移等成分,當有若干個循環語句時,算法的時間復雜度是由嵌套層數最多的循環語句中最內層語句的頻度f(n)決定的。這里T(n) = 3 * (n - 2) = O(N)。

方式三:快速矩陣冪

先了解一下,什么是矩陣快速冪

斐波那契數列的計算機算法是利用矩陣,二階三階都可以,這里舉例二階。

我們利用快速矩陣冪算法,可以在O(logN)時間內得到答案,這種方法還有一個優點,在計算較大n時顯得格外有效。

這里給出快速矩陣冪的模板,可借鑒:

const int N = 2;

struct Matrix {
    int mat[N][N];
    Matrix() {}
    Matrix operator * (const Matrix& b) const {
        Matrix result;
        memset(result.mat, 0, sizeof(result.mat));
        for (int i = 0; i < N; ++i) {
            for (int j = 0; j < N; ++j) {
                for (int k = 0; k < N; ++k) {
                    result.mat[i][j] = (result.mat[i][j] + this->mat[i][k] * b.mat[k][j]) ;
                }
            }
        }
        return result;
    }
};

Matrix MatPow(Matrix base, int n)
{
    Matrix result;
    memset(result.mat, 0, sizeof(result.mat));
    for (int i = 0; i < N; ++i) {
        result.mat[i][i] = 1;
    }

    while (n > 0)
    {
        if(n & 1) result = result * base;
        base = base * base;
        n >>= 1;
    }
    return result;
}
View Code

 

算法第一次練習賽指點

第一題就一個簡單的斐波那契數列呀,為什么泥萌都開二維數組,明明只要一個51的數組就夠了。

第二題開一個數組就好,為什么被誤導成開兩個數組呢?

第三題也是斐波那契數列,百度一下矩陣求斐波那契,一分鍾AC,不過還是建議熟悉矩陣快速冪的求解。

第四題絕對不是什么DP,掃描一遍O(N)解決就ok。

第五題?HINT里有寫使用優先隊列了,不懂的趕緊學習一下STL吧!

第六題?聽說你推出了公式直接求出答案?想一想結束時並不是每個機器人能量都用光就知道了,換個方法吧,比如二分~

 我要去做練習賽!

大家加油~

 

作者: AlvinZH

出處: http://www.cnblogs.com/AlvinZH/

本文版權歸作者AlvinZH和博客園所有,歡迎轉載和商用,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM