动态规划经典题之编辑距离
文章目錄
- 題目
- 解題思路
- (1)基本過程
- (2)動態規劃-遞歸
- (3)動態規劃-dp table
- 代碼
題目
leetCode72:編輯距離
編輯距離算法是一個非常實用的算法,它的作用是求出把一個字符串s1變為另一個字符串s2所需要的最少的操作數。
此過程中,只能對字符串進行插入、刪除或替換(其實還有一種隱形操作,就是略過)
比如把rad變為apple,就需要經過5步
解題思路
(1)基本過程
對于字符串類的題目,一般都會使用到兩個指針,這里面也不例外。上面的動圖中,展現的正是兩個指針i和j分別從后向前掃描兩個字符串。
在這個過程中如果j走完了,i還沒有走完的話,那么就需要把s1刪除,縮短為s2單
如果i走完了,但j沒有走完,那么就想要把s2中的插入到s1中
(2)動態規劃-遞歸
使用動態規劃解題,一定要考慮題目的狀態和選擇是什么?
- 狀態:這里顯然是i和j指針的位置
- 選擇:所選的操作,加上跳過,共有四種操作(skip,insert,delete,replace)
還有“base case”,也就是最簡單的情況是什么呢?這里其實就是上面所敘述的那兩種情況
首先采用遞歸解法說明。定義一個dp遞歸函數,函數形參分別就是i和j,該函數的返回值就是s1[0....i]和s2[0...j]的最小編輯距離,最終一步一步遞歸,可以得到問題的最終答案。
現在看該函數的base case,也就是如果j走完了,就把i刪除了;如果i走完了,就把j剩下的全部插入
int dp(i,j) {if i==-1return j+1;if j==-1return i+1; }如果遇到的字符相等,那么就什么也不做,直接跳過。也即是說s1[0....i]和s2[0....j]的最小編輯距離實際就是s1[0...i-1]和s2[0....j-1]的最小編輯距離。
int dp(i,j) {if i==-1return j+1;if j==-1return i+1;if(s1[i]==s[j])return dp[i-1][j-1];else}如果遇到的字符不相等,那么我們就需要進行選擇三種操作了。需要注意的是三種操作是肯定存在重疊問題,這也是遞歸不可避免的問題,因為一個字符變成另一個字符除了可以替換外,我也可以直接插入一個。
-
第一種操作:插入;遞歸函數為dp(i,j-1)+1。如果選擇了這種操作,那么就會直接在s1[i]中插入一個和s2[j]一樣的字符,此時s2[j]會被匹配到。注意操作數+1
-
第二種操作:刪除;遞歸函數為dp(i-1,j)+1。如果選擇了這種操作,那么就會直接把s[i]這個字符刪除掉。
-
第三種操作:替換;遞歸函數為dp(i-1,j-1)+1。如果選擇了這種操作就會直接把s1[i]替換為s2[j]。
于是偽代碼如下
int dp(i,j) {if i==-1return j+1;if j==-1return i+1;if(s1[i]==s[j])return dp[i-1][j-1];elsereturn min(dp(i,j-1)+1;//插入dp(i-1,j)+1;//刪除dp(i-1,j-1)+1;//替換) }還是那句話,這種解法一定存在大量重疊子問題。比如能過替換得到的結果也可以通過刪除后插入完成,這就是一條重復路徑,如果發現了一定重復問題,那么一定會有千千萬萬個重復問題,就像斐波那契數列一樣。而重疊子問題是可以通過備忘錄解決的
memo=dict(); int dp(i,j) {if((i,j) in memo)return memo[(i,j)];if i==-1return j+1;if j==-1return i+1;if(s1[i]==s[j])return dp[i-1][j-1];elsereturn min(dp(i,j-1)+1;//插入dp(i-1,j)+1;//刪除dp(i-1,j-1)+1;//替換) }(3)動態規劃-dp table
遞歸便于說明問題的解決思路,實際寫代碼時我們一般采用的還是自底向上的解法,也就是動態規劃數組。有了上面的基礎,我們很容易能夠理解,和公共子串,子序列那些題一樣**,這道題的數組也一定是一個二維數組**
其中dp[…][0]和dp[0][…]對應的就是base case(也即是把rad變成空串,那么需要3步),dp[i][j]存儲的是s1[0…i-1]和s2[0…j-1]的最小編輯距離。(dp函數的base case是i和j為-1,但是數組索引至少為0,所以要偏移1位)
代碼
class Solution { public:int minDistance(string word1, string word2) {int len1=word1.size();int len2=word2.size();vector<vector<int>> dp(len1+1,vector<int>(len2+1,0));//dp數組for(int i=1;i<=len1;i++)//base casedp[i][0]=i;for(int j=1;j<=len2;j++)dp[0][j]=j;for(int i=1;i<=len1;i++){for(int j=1;j<=len2;j++){if(word1[i-1]==word2[j-1])dp[i][j]=dp[i-1][j-1];elsedp[i][j]=min//min函數只有兩個形參,所以這樣寫(dp[i-1][j]+1,//插入min(dp[i][j-1]+1,//刪除dp[i-1][j-1]+1)//替換);}}return dp[len1][len2];} };總結
以上是生活随笔為你收集整理的动态规划经典题之编辑距离的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 文件系统管理
- 下一篇: 栈溢出笔记1.10 基于SEH的栈溢出