斐波那契數,一般用 F(n) 表示,造成的序列稱爲斐波那契數列。該數列由 0 和 1 開始,後面的每一項數字都是前面兩項數字的和。也就是:java
F(0) = 0, F(1) = 1 F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
給定 N,計算 F(N)。算法
示例 :數組
輸入:2 輸出:1 解釋:F(2) = F(1) + F(0) = 1 + 0 = 1.
因爲計算任何一個第n(n >= 2)項的數都須要知道其前面兩個數,即須要知道n-1和n-2是多少,而後兩個相加獲得結果,可是問題來了,要知道n-1,就要須要知道n-2,要知道n-2就須要知道n-3,會一直這樣的循環遞歸下去,一直到第一個數,第二個,第三個.......再反推回來。 那就很明顯了,你們第一時間想到的方法即是遞歸,就下來實現一下:code
方法一:遞歸實現blog
public class Solution { public int fib(int n) { if(n <= 1){ return n; } return fib(n-1) + fib(n-2); } }
問題分析:遞歸
先看一下遞歸圖:內存
因爲不少數的計算都要重複不少次,效率並不高,時間複雜度達到了 O(2^n),是斐波那契數計算中 時間複雜度最大,最不可取的方法。io
空間複雜度:O(n),堆棧中須要的空間與 N 成正比,堆棧會跟蹤 fib(n) 的調用,隨着堆棧的不斷增加 若是沒有足夠的內存則會出現StackOverflowError異常。class
注:定義爲int型時,最大隻能求到n = 46,f(46) = 1836311903, 而 f(47) = -1323752223,由於超出了int 型數值的最大範圍。效率
使用遞歸的同時,使用記憶化方式存儲已經計算過的數據,減小沒必要要的重複計算,可使時間複雜度降到 O(N),同時空間複雜度也是O(N)。具體的實現是使用一個數組,把每次計算過的值都存儲進去,當再次使用這個數的時候,直接返回,不須要再進行遞歸。
方法二:記憶化自底向上遞歸
public class Solution { public int fib(int n) { if(n <= 1){ return n; } int[] memo = new int[n+1]; memo[1] = 1; for(int i = 2;i <= n; i++){ //自底向上填充數組,一直到須要的那個數 memo[i] = memo[i-1] + memo[i-2]; } return memo[n]; } }
限於水平有限,斐波那契數的實現還有不少種方法,不能一一列舉,當其中大部分都有相似的思想。
水文中若有不許確或是錯誤之處,還望指出。謝謝~~~
下一篇:LeetCode.62——不一樣路徑