衆所周知,在面試中最難,也是大公司最容易考的就是動態規劃,因此今天打算開撕動態規劃,以前只是對於單個的題目知道解法,不過期間一久就忘記了,今天開始要完全的理解方法論再到實踐,但願老天保佑可以一週搞定!面試
一.經過一個小例子瞭解方法論:算法
一個例子,如上圖:編程
求從起點到終點的最短路徑:數組
這是一道最基本的動態規劃問題,若是不使用動態規劃可使用窮舉進行求解,路徑大概存在2的k次方。利用動態規劃求解主要步驟:數據結構
1. 找出規劃的初始狀態:對此,找出第一個子問題的解從而能夠在後面的內容中利用該解來做爲後面狀態的條件,在這一問題中初始狀態就是最鄰重點的c點到終點的最短距離。 函數
2. 規劃決策路線,這一問題的決策路線是將邊界從起點不斷的向終點進行移動,以下圖。有些問題是從起始狀態向終點逐漸向最終狀態進行推動,知道最後到達最終學習
狀態。優化
2. 轉化方程:對於動態規劃其求解在於,子子問題->子問題->問題,利用上一狀態來求解下一狀態,找出先後的關係,最終求解。以下圖,該題中的關係很是簡單,就是利用前一子問題的解加上當前結點到下一個的最短路線。 設計
3.收斂條件:找出最終狀態的終點在哪3d
4.適用的優化原則:一個最優決策序列的任何子序列自己必定是相對於子序列自己的初始和結束狀態的最優決策序列。
二. 動態規劃的設計要素
在第一部分中寫了一些關於求解動態規劃的我的見解,下面幾條是教學視頻中總結並列舉動態規劃基本步驟:
1.問題建模,優化的目標函數是什麼?約束條件是什麼?
2.劃分子問題(邊界)
3.子問題和父問題的依賴關係(遞推方程)
4.知足優化,判斷是否知足優化原則
5.最小子結構,最小函數值是什麼,初值是什麼?
以上五點能夠總結爲動態規劃的方法論,之後刷題中並不是全部問題均可以根據以上五點進行教科書式的照搬,可是系統的分析動態規劃問題,以上五點是對於分析動態規劃問題很是重要的步驟,尤爲對於初學者來說。以下圖,利用一個矩陣鏈相乘的例子,來利用動態規劃的方法來求解此問題。
1.問題建模,優化的目標函數是什麼?約束條件是什麼?
此問題的目標函數在於找出矩陣相乘找出最小的結果,即:
min = P[0,i]*P[i+1,n]能夠獲得最小值。
2.劃分子問題(邊界)
子問題的邊界,首先將初始劃分邊界的i值從0-n所有遍歷一遍,找出相乘獲得的最小值,此時的i則是劃分出來的子區間,再對於[0,i]與[i+1,n]中繼續按照以前遍歷進行劃分,依次類推,直到不可分。找到局部的最小值,從而獲得最優解。
3.子問題和父問題的依賴關係(遞推方程)
遞推方程,以下圖:
所謂遞推方程最重要的就是一層一層的向最終結果遞進,在每一層中遍歷全部的元素,找到這一層子問題最優的解,並運用在下一層中。直到達到最終狀態,這就是所謂的記憶化編程。
4.知足優化,判斷是否知足優化原則
子問題優化,總體問題也會隨之優化,找出的子問題的解也是子過程的最優解。
5.最小子結構,最小函數值是什麼,初值是什麼?
最小子結構就是第一次對於整個輸入的數組進行遍歷找出,分隔的最小的點i,這就是初值。
三.動態規劃的遞歸實現:
1.部分僞碼
以上爲前一題矩陣鏈相乘的遞歸實現的僞碼:
1.利用m來記錄最終結果的大小q
2.s來記錄劃分的位置k
3-7. 遍歷i到k和k+1到j並經過遞歸調用進行計算,而且不斷刷新k和q的值
8.返回最終結果
2. 有關複雜度:
3.產生子問題的劃分過程:
遞歸實現的主要的侷限在於同一個子問題會被屢次實現,因此其時間複雜度會比較高,解決這一問題能夠經過記錄子問題結果的方式來實現,下面動態規劃的迭代實現。
四.動態規劃的迭代實現:
動態規劃的迭代實現是後面解題的最經常使用的方式,比起遞歸的方法,迭代的時間複雜度會小不少,可是須要一個數據結構做爲備忘錄對每次子問題的結果進行記錄,這樣能夠避免屢次重複計算:
1.迭代計算的關鍵:
1.每一個子問題只計算一次
2.從最小的子問題算起,考慮計算順序,保證後面的計算過程當中前面計算的結果能夠用到。
3. 用數據結構做爲備忘錄進行存儲
4.設置標記函數,用標記函數對每一步的解法實施標記,最後獲得最終的解法。
2. 對於子問題的劃分能夠遞歸擴大其長度:
如圖,子問題長度從2到8,對於每個長度的劃分能夠列出全部可能的解
r=2時 存在7種
r=3時 存在6種
r=4時 存在5種
r=5時 存在4鍾
以此類推,由此可在每次劃定r時找出最小值
3.相關僞碼
1.初始化最初子結構
2.從2到n遍歷r可能的鏈長
3-4.在鏈長固定的狀況找出劃分的左右邊界i和j,i與j的距離始終爲r
5. 在備忘錄中經過前一子結果得出當前結果,一次劃分的初始結果
6. 記錄劃分位置k
7. 經過點k再在i和j之間進行劃分
8-11.找出最優的子劃分的位置k以及值t,第八行爲狀態轉移方程
4.時間複雜度:
5.備忘錄m,標記表格n
五.總結
今天認真系統的學習了一下動態規劃,發現之前的學習和刷題都是像走馬觀花同樣,浪費了不少時間,而且不得要領。目前距離徹底理解動態規劃還有很長的學習距離,可是打開的系統學習的第一部,真的很重要,下面幾條是我結合教學視頻上的幾點進行總結:
1. 最重要的就是對於動態規劃狀態的劃分,最終狀態是什麼,從什麼狀態能夠到達最終狀態,又從初始狀態下怎麼達到那一狀態。換言之,就是對於子問題的劃分,將問題求解轉化爲多步運算或者多步判斷的過程.
2.肯定該問題可否使用動態規劃,經過極小值或者極大值做爲判斷
3.解題的關鍵在於定義轉化方程,例如在最小矩陣鏈中,一個問題結果能夠在若干個子選項中選出一個最小的方案,加上當前數值放在備忘錄中
4.利用數據結構創建備忘錄,常見數組,矩陣,有時也可能有哈希表的存在
5.有時還須要創建狀態轉移矩陣,由於可能不只僅是數值,並且還存在數值相對應的狀態,例如索引和其餘屬性須要記錄。
好長,,,,,第一次寫的這麼認真,過段時間複習但願可能看懂,若是一年前開始接觸算法題能這樣作的話,我可能心在也有工做了,,,,心塞