1. 程式人生 > >DataWhale——遞迴和動態規劃

DataWhale——遞迴和動態規劃

本文大量參考了部落格演算法-動態規劃 Dynamic Programming--從菜鳥到老鳥裡的內容,加上一點自己的理解。

遞迴

遞迴和動態規劃很是相近,但又有所區別。從定義上看,遞迴在數學上可以表示為“數學歸納法”;由於我個人對數學歸納法的解法實在是印象深刻,但凡遇到之類的問題,都會用數學老師教的解法來做:1.找到初始狀態\(a_0\);2.找到遞迴定義式。實際上,遞迴程式也是這麼寫的。

需要注意的是,遞迴是非常消耗記憶體的,遞迴層次非常深的程式通常有很長的呼叫鏈,計算機為了保證狀態的返回又不得不將這些呼叫鏈一一儲存。但是,遞迴的一大好處是,它形式上非常好理解。由於我們只要搞懂初始狀態和遞迴形式,剩下的只要有足夠大的空間和足夠長的時間,就可以解出來。

由於遞迴的這些特性,通常我們遇到遞迴類問題時,可以先用遞迴思路做出來(往往是更簡單的,但也有例外),再看是否有必要,將遞迴演算法改進為有狀態儲存的備忘錄演算法。試圖直接找出備忘錄演算法往往是很困難的,關於“樹”的很多問題,包括遍歷、查詢等,往往是遞迴不到十行,迴圈要二三十行。

動態規劃

這裡建議看上面的部落格,總結得非常好。這部分我也是剛學,就只提煉自己的理解。動態規劃的問題往往可以用遞迴來做,倒過來也是一樣的。那麼它們具體的區別是什麼呢?這就涉及到動態規劃關注的兩個問題了:1.最優子結構;2.重疊子問題

最優子結構的意思是,一個問題的最優解是從多個子問題最優解中找出來的。舉個例子,當一家公司要考慮開一個新專案時,往往需要綜合多個領域,包括財務、技術、人員等等,老總自然不可能一個個自己琢磨;他會把這個調研任務分為不同領域交給各個專業的手下,從手下得到每個領域的最優方案,再從這些方案中提煉出一個最佳方案。需要注意的是,每個子問題的最優解可以從它的所有最優子孫問題解中找到,有形式上的遞迴

重疊子問題就很好理解了,就是針對遞迴問題中不儲存狀態的問題。遞迴解法是通過計算機的呼叫鏈來返回狀態的,所以每次遇到同樣問題都要再算一遍。針對這種情況,動態規劃要將每一個問題的解都儲存下來,在自底向上的過程中,會很方便進行查詢。

我個人對動態規劃還有一個理解。雖然無論是遞迴還是動態規劃,我們都需要找到初始狀態和遞迴定義式,但是程式或者演算法的進行過程是完全不同的。遞迴的演算法是從一棵樹的頂點一個個向下查詢,直到初始狀態,然後再一層層返回;而動態規劃是從初始狀態逐次遞推,並且儲存遞推過程中的每一個狀態量。簡而言之,一個自頂向下,一個自底向上

當然這裡只是很乾的理論,更深層次的理解必須要經過實戰才能獲得。具體的例題可以看上文部落格的那幾個。這裡還有一個補充部落格,提到了動態規劃的另一種思路——自頂向下。其實就是把返回值儲存在陣列中(但是文章利用全域性陣列的方式不推薦,要麼外面套一層函式,或者用閉包)。這種方法最大的問題是,沒有解決呼叫鏈很長佔用記憶體的問題,所以只是一個補充瞭解但是不推薦。

補充部落格連結:遞迴和動態規劃