1. 程式人生 > 其它 >斐波那契數列的非遞迴實現

斐波那契數列的非遞迴實現

非遞迴實現,也就是迭代實現。

問題引入

有一對兔子,從出生後第3個月起每個月都生一對兔子,小兔子長到第三個月後每個月又生一對兔子,假如兔子都不死,問每個月的兔子對數為多少?

程式分析

兔子的規律為數列1,1,2,3,5,8,13,21 … ,屬於斐波那契數列問題。該數列有一個規律: F(0) = 1 , F(1) = 1, F(n) = F(n-1) + F(n-2)(n>=2) …

由此可以用遞迴的方法實現,這樣寫出的程式碼比較簡潔.

public class Prog1 {
    public static void main(String[] args) {
    int n = 50;
    for (int i = 1; i <= n; i++) {
        System.out.println("After " + i + " mouths, the number of rabbit is " + fun2(i));
        }
    }
    
    public static long fun2(int n) {
        if (n == 1 || n == 2)
            return 1;
        else {
            return fun(n-1) + fun(n-2);
        }
    }
}

這樣的遞迴演算法雖然只有簡單的幾行,但是效率卻很低。為什麼呢?我們可以分析其遞迴呼叫的時間複雜度:

時間複雜度 —– O(2^N)

由於使用遞迴時,其執行步驟是:要得到後一個數之前必須先計算出之前的兩個數,即在每個遞迴呼叫時都會觸發另外兩個遞迴呼叫,例如:要得到F(10)之前得先得到F(9)、F(8),那麼得到F(9)之前得先得到F(8)、F(7)……如此遞迴下去 。

這樣的計算是以 2 的次方在增長的。

除此之外,我們也可以看到,F(8)和F(7)的值都被多次計算,如果遞迴的深度越深,那麼F(8)和F(7)的值會被計算更多次,但是這樣計算的結果都是一樣的,除了其中之一外,其餘的都是浪費,可想而知,這樣的開銷是非常恐怖的 。

所以,如果在時間複雜度和空間複雜度都有要求的話,我們可以用以下的非遞迴演算法來實現。

非遞迴演算法

時間複雜度為*O(N)*,空間複雜度為*O(1)*

思路:藉助兩個變數 first 和 second ,每次將 first 和 second 相加後賦給 third ,再將 second 賦給 first ,third 賦給 second,如此迴圈。

public class Prog1 {
    public static void main(String[] args) {
        int n = 50;
        for (int i = 1; i <= n; i++) {
            System.out.println("After " + i + " mouths, the number of rabbit is " + fun2(i));
        }
    }
    
    public static long fun(int n) {
        long first = 0;
        long second = 1;
        long third = 1;
        for (int i = 2; i <= n; i++) {
            third = first + second;
            first = second;
            second = third;
        }
        return third;
    }
}