斐波那契數列的非遞迴實現
阿新 • • 發佈:2022-03-05
非遞迴實現,也就是迭代實現。
問題引入
有一對兔子,從出生後第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; } }