斐波那契數列的幾種解法


斐波那契數列一般都用於介紹遞歸的思想。

我們知道斐波那契數列的通項公式(n>1)如下:

F(n) = F(n-1) + F(n-2)

按照這個公式寫個代碼就很容易了:

int fibonacci(int n) {
    if (n == 0 || n == 1) {
        return n;
    }
    return fibonacci(n-1) + fibonacci(n-2);
}

這種代碼簡單又優雅,但是缺點也很明顯,就是慢:

又慢又占空間。

這是為什么呢?

我們來看看遞歸都做了什么,以n=5為例,如下圖:

這里會有很多的重復計算過程,這個重復計算的過程叫做遞歸棧,遞歸最大的毛病就是遞歸棧里重復的東西太多。

觀察上圖,如果從下向上,效果會更加的好,可以借助數組來實現,我們知道斐波那契數列其實就是這樣的一個數列:

0,1,1,2,3,5,8...

只要將第一和第二項算出來保存在數組中,后面的項就很好計算了:

public int Fibonacci2(int n) {
        int[] fib = new int[45];
        fib[0] = 0;
        fib[1] = 1;
        for (int i = 2; i <= n; i++) {
            fib[i] = fib[i - 1] + fib[i - 2];
        }
        return fib[n];
    }

n=5的時候,這個數組最終是這樣的[0,1,1,2,3,5,......],此時的時間復雜度僅僅是O(n),比遞歸的O(2^n)好太多了:

僅僅消耗了17ms,是原先的5.8%左右。

但是,繼續觀察上面的數組:

[0, 1, 1, 2, 3, 5],我們會發現這個數組中,f(0)和f(2)並沒有用到,這兩個其實可以精簡掉,於是代碼變成了這樣:

public int Fibonacci(int n) {
        if (n == 0 || n == 1) {
            return n;
        }
        int a = 0;
        int b = 1;
        int c = 0;
        for (int i = 2; i <= n; i++) {
            c = a + b;
            a = b;
            b = c;
        }
        return c;
    }

n=5的情況下,這個循環只會計算f(1),f(3),f(4)和f(5)的值,並不用數組去保存,因此空間也節省了下來。

另外我試了試C和Java語言用第三種解法的速度差異,發現C語言還是很有優勢的:

同樣的算法竟然只用了5ms。


免責聲明!

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



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