牛客網常見算法思路 (十二)動態規劃

有用麻煩點個贊哦

如何理解動態規劃

經典題:給定一個數組arr,arr中所有的值都爲正數且不重複。每個值代表着一種面值的貨幣,每種面值的貨幣可以使用任意張,在給定一個整數aim代表要找的錢數,求換錢有多少種哦方式

本題可以體現
暴力搜索方法->記憶搜索方法->動態規劃方法->狀態繼續化簡後的動態規劃方法

暴力搜索

arr={5、10、25、1},aim=1000
1、用0張5元的貨幣,讓[10,25,1]組成剩下的1000,最終方法數記爲----res1
2、用1張5元的貨幣,讓[10,25,1]組成剩下的995,最終方法數記爲------res2
3、用2張5元的貨幣,讓[10, 25,1]組成剩下的990,最終方法數記爲-----res3
如此類推…
201、用200張5元的貨幣,讓[10, 25,1]組成剩下的0,最終方法數記爲-----res201

定義遞歸函數:int p1(arr,index,aim),他的定義是如果用arr[index…N-1]這些面值的錢組成aim==1000,返回總的方法數

評價:
寫出來可能比較簡單,但實際上有大量的重複部分,如0張10元,2張5元 與 1張10元,0張5元后續部分的匹配是一樣的

記憶搜索算法 (其實已經可以認爲是動態規劃了)

因爲這個過程中arr不變,變得是index和aim,以p(index,aim)進行遞歸,準備一個hashmap,
1、每計算完一個p(index,aim)都將結果放入map中,index和aim組成共同的key,返回結果爲Value
2、要進入一個遞歸過程時,先以index和aim註冊的key在map中查詢,如果已存在則直接取值

動態規劃方法

arr長度爲N,則生成行數爲N,列數爲aim+1的矩陣dp。
dp[i][j]的含義是arr[0…i]貨幣的情況下,組成錢數j有多少種方法,最終目標爲dp[N][aim+1],dp[i][j]=sum(dp[i-1][0到j])
改進:dp[i][j]=dp[i][該行上一個要統計的格子]+dp[i-1][j](上一行用一個格子)時間複雜度O(N*aim)

動態規劃和記憶搜索方法的聯繫

1、記憶搜索爲某種形態的動態規劃方法
2、記憶搜索不關心到達某個過程的路徑,只是單純的計算遞歸過程,避免重複。3、動態規劃的方法則是規定好每一個遞歸過程的計算順序,依次進行計算,後面的計算過程嚴格依賴前面的計算過程。
4、兩者都是空間換時間,也有枚舉過程,區別在於有無規定的計算順序

解題步驟:

1、實現暴力遞歸
2、暴力遞歸中查看哪些函數可以代表遞歸過程
3、找到代表遞歸過程的參數之後,記憶化搜索的方法非常容易實現
4、分析記憶搜索的依賴路徑,找到動態規劃
5、通過動態規劃嘗試化簡

案例一

有n級臺階,每次走一級或者兩級,問有多少種方法走完,
思路
1、可以用斐波拉切

案例二

給定矩陣m,從左下角開始每次只能向下或者向右走,路徑上數字加起來的和爲路徑和,找出最小的路徑和
思路
1、生成和m一樣大小的矩陣dp
2、第一行的最小路徑和第一列的最小路徑可以直接累加走出(直走)
3、dp[i][j]=m[i][j]+min(dp[i-1][j],dp[i][j-1])

案例三

給定數組arr,返回arr的最長遞增子序列長度。2,1,5,3,6,4,8,9最長遞增子序列13489,返回5
思路
生成長度爲n的數組db,db[i]爲以arr[i]的個數結尾的情況下最長遞增子序列的長度
過程:檢索i時從左邊找比i小的數,選bp最大的+1作爲自己bp的值。
dp[i]=max{dp[j]+1(0<=j<i,arr[j]<arr[i])}

案例四

給定兩個字符串str1和str2,返回兩個字符串最長公共子序列(子序列不一定要連續)
思路
str1長度爲M,str2長度爲N,生成大小爲M*N的矩陣dp。dp[i][j]的含義是str1[0…i]與str2[0…j]的最長公共子序列的長度
dp求法如下
1、dp第一列,dp[i][0],代表str1[0…i]與str2[0]的最長公共子序列長度。str2[0]只有一個字符,所以dp[i][0]最大爲1。如果str1[i]==str2[0],則領dp[i][0]爲1,一旦dp[i][0]爲1,則令dp[i+1…M][0]全部爲1,。
2、dp第一行與第一列同理,一旦dp[0][j]被設爲1,則令dp[0][j+1…N]全部爲1
3、其他位置dp[i][j]爲一下三種情況
情況一:爲dp[i-1][j]。代表着str1[0…i-1]與str2[0…j]的最長公共子序列長度
情況二:同理可知有可能是dp[i][j-1]
情況三:如果str[i]==str[j],還可能是dp[i-1][j-1]+1的值
選擇三者中最大的值即可

案例五

揹包問題
一個揹包承重W,有N件物品,每件物品有他們的價值,記錄在數組V也有他們的重量,記錄在數組W,問如何選擇揹包總價值最大
思路
從1到n,一件一件考慮是否加入揹包
假設dp[x][y]是前x件物品,不超過重量y的時候的最大價值:枚舉第x件物品的情況:
情況一:如果選擇第x件物品,則前x-1件物品不能超過y-w[x]
情況二:不選擇x,前x件物品,x-1件物品不能超過y

所以dp[x][y]可能等於dp[x-1][y],也就是不取第x件物品時,價值和之前一樣
也可能等於dp[x-1][y-w[x]]+v[x]
選擇最大的
行數爲物品數量n,列數爲揹包重量w,從左到右,從上到下,依次計算即可。

案例六

給定兩個字符串str1和str2,在給定三個整數ic,dc和rc,分別代表插入刪除和替換一個字符的代價。返回將str1編輯成str2的最小代價
思路
假設str1長度爲m,str2長度n,生成大小爲(M+1)*(N+1)的矩陣dp,dp[i][j]的值代表代表str1[0…i-1]編輯成str2[0…j-1]的最小代價

1、dp[0][0]代表str1空字符串編輯成str2空字符串的代價0.
2、矩陣dp第一列即dp[0…M][0],dp[i][0]表示str1/[0…i-1]編輯成空字符串的最小代價,即都刪除dp[i][0]=dc*i

3、矩陣第一行同理,爲str1空字符串編輯成str2的代價dp[0][j]=ic*j
4、其他位置先從左到右,從上到下,dp值只會來自四種情況
情況一:(從多出來的部分減一個)
str1[0…i-1]先編輯成str[0…i-2],也就是刪除str1[i-1],再編輯成str2[0…j-1],dp[i-1][j]就表示str1[0…i-2]編輯成str2[0…j-1]的最小代價,所以dp[i][j]可能等於dc+dp[i-1][j]
情況二: (從少的部分加一個)
其實和一同理,dp[i][j-1]+ic
情況三:(替換一個字符)
dp[i-1][j-1]+rc
情況四:str1和str2新增的字符剛好相等。dp[i-1][j-1]
選擇最小的值作爲dp[i][j]的值

有用麻煩點個贊哦

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