理解動態規劃

動態規劃是一個經典而實用的算法,常常在面試題中出現。html

以最著名的刷題網站leetcode爲例,目前有147道動態規劃算法題,佔比約 13% 。前端

其重要性可見一斑~git

這篇文章就來詳細分析一下動態規劃相關知識點。github

定義

綜合維基百科和《算法導論》的說法,能使用動態規劃解決的問題必須包含下面兩個要素:面試

  1. 重疊子問題。
  2. 最優子結構。

重疊子問題很好理解,遞歸就是解決重疊子問題的一種方式。 簡單理解就是父問題和子問題處理方式一致,可是規模不一樣。 下面來重點須要分析最優優子結構。算法

最優子結構

什麼是最優子結構?

問題的最優解包含其子問題的最優解。數組

或者說就是經過子問題的解能夠推導出父問題的解。記住是子問題的解而不是子問題自己。緩存

如何理解?舉個例子:bash

給定一個整數數列 [12, 18, 21, 60],求下面兩個問題前端工程師

  1. 偶數個數。
  2. 最小公倍數。

對於第一個問題就是具備最優子結構,由於將問題(數組)拆分後求解的結果能夠用於問題自己的解。

子數組的偶數個數 + 當前數是否爲偶數 ? 1 : 0 = 數組的偶數個數

第二個問題就不具備最優子結構,將問題(數組)拆分後求得的解不能直接用於問題自己的解。

子數組的最小公倍數 + 數組某個元素 =/=> 當前數組最小公倍數

第一個問題咱們不須要關心子數組的內容,只須要關心子數組的結果便可,而第二個問題咱們須要知道子數組的組成。

固然有專業術語能夠來表述這種情形,叫作「無後效性」。

如何找到最優子結構?

《算法導論》中給出的通用模式(套路)以下:

  1. 將問題進行拆分,一般會拆分紅多個待求解的子問題。
  2. 假定已經知道了子問題的最優解。
  3. 給定最優解選擇後,肯定會產生哪些子問題,對子問題空間進行刻畫。
  4. 證實子問題的解是原問題最優解的組成部分。

雖然我對描述語言進行了精簡,可是看起來仍是有些囉嗦。再用一句話來歸納就是「不斷縮減問題的規模」,記住是縮減規模不是縮減條件。

以爬樓梯問題爲例進行說明:

題目:一我的上樓梯,樓梯有n階臺階,一次能夠上1階或2階。問有多少種上樓梯的方式。

對於這個問題使用動態規劃來考慮,分解的子問題應該是:

爬 n - 1 階樓梯有多少種方式
爬 n - 2 階樓梯有多少種方式
複製代碼

而縮減條件的方式是(這是錯誤的思路)

爬 n 階樓梯每次只爬1階有多少種方式
爬 n 階樓梯每次只爬2階有多少種方式
複製代碼

優點

理論上來講,大多數問題均可以經過(暴力)枚舉來解決。可是一般枚舉是下冊,由於效率過低,沒法在有限的時間或空間內獲得結果。

因此咱們若是將動態規劃算法和枚舉相比,那麼它至少具備兩個優點。

  • 篩選。父問題必定是從子問題的最優解獲得,也就是說子問題的非最優解是不會被考慮和計算的。
  • 緩存。子問題的最優解會被記錄下來,用於推導父問題的最優解,從而避免重複計算。

例子

借用知乎答主阮行止的一個例子進行說明。

題目:一個國家的鈔票面額分別是1元、5元、11元,如何用最少的鈔票湊出15元?

先看解答過程:

dp(n)函數表示湊出n元時須要的鈔票數量。 那麼n = 15時考慮可能由 n=10 時加一張5元,n=14 時加一張1元,n=4 時加一張11元。用公式表述以下:

dp(15) = min{dp(10) + 1, dp(14) + 1, dp(4) + 1}

加上已知條件:dp(11) = dp(5) = dp(1) = 1,整個推導公式以下圖:

{% asset_img dp15.jpg %}

而後再結合起來理解動態規劃算法的優點。

  • 篩選。例如 dp(15) = dp(5) + dp(5) + dp(1) + dp(1) + dp(1) + dp(1) + dp(1) 這種解顯示是不會被計算的,由於它不是某個子問題的最優子結構。這樣的好處是避免了無效計算。
  • 緩存。例如 dp(3) = dp(2) + 1 = [dp(1) + 1] + 1 這個子問題的最優解會被重複用到,因此能夠用數組來緩存子問題的最優解,從而避免了重複計算。

思考題

某公司出售一段長度爲99米可切割的鋼條,已知鋼條的價格爲Pi(i=1,2,3...),鋼條長度均爲整數。長度價格關係以下:

長度i    1    2    3    4    5    6    7    8    9    10
價格Pi   1    5    8    5    10   17   17   20   24   30
複製代碼

求收益最大的切割方案。


參考:


原文連接:tech.gtxlab.com/dp.html 做者信息:朱德龍,人和將來高級前端工程師。

相關文章
相關標籤/搜索