leetcode-72. 編輯距離
阿新 • • 發佈:2021-07-17
求解方法
知道了編輯距離的定義,那麼如何求最小編輯距離呢?這裡用到了動態規劃的思想。
用例子來說明,假如我們要求解 jary和jerry的最小編輯距離,那麼首先要建立如下矩陣:
Φ | j | a | r | y | |
Φ | 0 | 1 | 2 | 3 | 4 |
j | 1 | ||||
e | 2 | ||||
r | 3 | ||||
r | 4 | ||||
y | 5 |
這個矩陣什麼意思呢?第一行是字串jary,第一列是字串jerry,每個標有數字的單元格代表了兩個字串的子串的最小編輯距離。第二行第二列的0代表兩個字串都取空子串的時候,編輯距離就是0(子串相等);第二行第三列的1代表當jerry的子串取空,jary的子串取j時,兩個子串的最小編輯距離是1(給jerry的子串插入j)。其他的依次類推,可以很容易得出當前矩陣中的第二行和第二列的數字。
而我們最終要求的兩個字串的最小編輯距離對應的就是矩陣右下角的那個單元格,它代表當jary子串取jary,jerry子串取jerry時,兩個子串的最小編輯距離,也就是兩個字串的最小編輯距離。
這裡我先直接說怎麼求,然後再解釋原理。看下面的矩陣,我在中心空白的位置標上了從x1到x20,這裡x後面的數字代表我們求解時的順序。
j | a | r | y | ||
0 | 1 | 2 | 3 | 4 | |
j | 1 | x1 | x6 | x11 | x16 |
e | 2 | x2 | x7 | x12 | x17 |
r | 3 | x3 | x8 | x13 | x18 |
r | 4 | x4 | x9 | x14 | x19 |
y | 5 | x5 | x10 | x15 | x20 |
如果按順序求解的話,那麼在求解每一個值的時候,它的左、上、左上三個位置的單元格值肯定都是已知的,將這三個單元格里的值分別定義為left、top、leftTop,則要求解的單元格的值v為:
若單元格橫向對應的字元和縱向對應的字元相等則為cost為0
如果不等:
cost =min(left+1,top+1,leftTop+1)
因此下面按照動態規劃進行求解:
dp(i, j) 函式的定義是這樣的:
def dp(i, j) 表示 s1[0..i] 和 s2[0..j] 的最小編輯距離
base case:
dp[..][0]
和dp[0][..]
對應 base case
狀態轉移方程:
if s1[i] == s2[j]:
return dp(i - 1, j - 1) # 啥都不做
else:
return min(
dp(i, j - 1) + 1, # 插入
dp(i - 1, j) + 1, # 刪除
dp(i - 1, j - 1) + 1 # 替換
)
class Solution {
public:
int minDistance(string word1, string word2) {
int m = word1.length();
int n = word2.length();
int dp[m+1][n+1];
//base case
for(int i = 0; i <=m; i++)
dp[i][0] = i;
for(int j = 0; j <=n; j++)
dp[0][j] = j;
for(int i = 1; i <= m; i++)
for(int j = 1; j<= n; j++){
if(word1[i-1]==word2[j-1])
dp[i][j] = dp[i-1][j-1];
else
dp[i][j] = min(dp[i-1][j]+1,min(dp[i][j-1]+1,dp[i-1][j-1]+1));
}
return dp[m][n];
}
};