算法數據結構面試分享(九)從斐波那契數列初識遞歸

從斐波那契數列初識遞歸

斐波那契數列指的是這樣一個數列 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368.. 今天我們來一起回顧一下這個數列,重新認識一下遞歸的原理。

大家還記得我們的課本上講遞歸的時候,先引入的是它的算法定義,然後帶大家去編碼的對吧?說到這裏不得不吐槽下中國的教育改變了我們思考問題的方法,以致於我們在處理一個真正問題的時候很難指出來這是一個可以用遞歸解決的問題。我這裏先留一道題哈,下節課我們一起來分析一下,有N個臺階,假設我們每次擡腳,可以選擇走一個臺階,也可以選擇走兩個臺階,那麼請問,完成這N個臺階有多少種走法?言歸正傳,我們繼續說遞歸(今天我們的思路和之前其他的算法題會有所區別)。

一、什麼樣的問題可以用遞歸?

    所有能夠用遞歸解決的問題都會滿足如下幾個條件:

  1. 問題是可以分解的,大問題可以劃分爲若干子問題
  2. 子問題在某種程度上還是原來的問題,根本的性質是一樣的
  3. 子問題的規模比原問題小
  4. 子問題解決了,我們就能解決更大規模的問題
  5. 子問題無限分解也是有終止條件的,而且終止條件滿足時,問題的解是顯而易見的         

那我們一塊再來看下斐波那契數列,是不是滿足這樣的規律。

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

F(n) = 1; n =1,2

F(n) 能劃分爲小問題 F(n-1) 和 F(n-2), 而 F(n-1) = F(n-2) + F(n-3), 是不是 F(n-2), F(n-3) 解決了才能求出 F(n-1), 進而求出F(n)呢? 他們的問題都是F問題,而且,F(1)=1, F(2) = 1; 是不是F問題存在終結條件呢?

二、如何用遞歸解決問題?

    經過分析之後我們斷定這是一個遞歸問題,我們需要找的就是遞歸公式了。找到遞歸公式之後我們需要找到終結條件和它的值。 從上面的例子中,如果給了遞歸公式了,我覺得這道題就沒有什麼意思了。大家可以等我下一篇文章,我們會從問題出發。上面的數列當中,我們會發現第一個和第二數都是一個特例,之後的數等於前面兩個數之和。

三、遞歸的真正原理和替代算法是什麼

    我們再看F(n) = F(n-1) + F(n-2), 大家知道F(100)的求解過程嗎?這裏面存在兩個過程,遞推和回溯。要求F(100) 我們先要求F(99), F(98), 而 F(98)先要求出F(97), F(96), 知道F(1), F(2);

    現在我們求出了F(1), F(2), 我們再回去求F(3), 進而F(4), 一直到F(100). 

    從上面的求解過程中,大家發現了在遞推的過程中,我們把子問題是不是都依次入棧了,知道我們求出F(1,2)我們再將問題依次出棧,之後最後一個問題F(100). 所以大家能夠發現,遞歸的本質就是入棧、出棧的問題,所以遞歸的複雜度會很高。同時,我們能夠用棧來優化遞歸。

四、遞歸的代碼模式

遞歸的代碼中包含兩個重要部分, 終止條件時直接返回,否則縮減問題規模調用它本身。

public static int F(int n)

{ if (n > 0) { if (n == 1 || n == 2) return 1; else { return F(n - 1) + F(n - 2); } } else { throw new ArgumentException("The N should not a negative number."); } }


歡迎大家關注我的公衆號,還有我的系列視頻教程, 數據結構與算法 微軟經典算法面試題輔導。大家有什麼更好的解法,也歡迎討論哈。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章