最小編輯代價
問題描述
給你兩個單詞 word1 和 word2,請你計算出將 word1 轉換成 word2 所使用的最少操作數 。你可以對一個單詞進行如下三種操作:
- 插入一個字元
- 刪除一個字元
- 替換一個字元
示例:
輸入:word1 = “horse”, word2 = “ros”
輸出:3
解釋:
horse -> rorse (將 'h' 替換為 'r')
rorse -> rose (刪除 'r')
rose -> ros (刪除 'e')
分析問題
根據題目要求,你可以對任意一個單詞進行增、刪、改三種操作,題目給定兩個單詞,所以一共有2*3=6中操作。但是這裡包含了一些重複的情況,假設給定的單詞是A和B。
- 對單詞A刪除一個字元和對單詞B增加一個字元是等價的。比如單詞A是「abc」,單詞B為「bc」時,我們既可以刪除單詞A的第一個字元a,得到相同的「bc」,也可以在單詞B的開頭添加一個字元a,得到相同的「abc」。
- 同理,對單詞B刪除一個字元和對單詞A插入一個字元也是等價的。
- 對單詞A替換一個字元和對單詞B替換一個字元也是等價的。
所以本質上不同的操作只有三種,即
- 在單詞A中插入一個字元
- 在單詞A中刪除一個字元
- 修改單詞A中的一個字元
這樣我們可以把原問題拆分成若干個子問題,我們假設A=”horse”,B=”ros”。下面來看一下如何具體操作。
- 在單詞A中插入一個字元:如果我們知道「horse」到「ro」的編輯距離為a,那麼「horse」到「ros」的編輯距離不會超過a+1。因為我們只需要在「horse」的末尾添加一個字元s即可。
- 在單詞A中刪除一個字元:如果我們知道「hors」 到 「ros」的編輯距離為b,那麼「horse」到 「ros」的編輯距離不會超過 b + 1。因為我們只需要刪除「horse」的最後一個字元e即可。
- 修改單詞A中的一個字元:如果我們知道「hors」到「ro」的編輯距離為c,那麼「horse」到 「ros」的編輯距離不會超過 c + 1。因為我們只需要把「horse」的最後一個字元e修改為s即可。
那麼從「horse」變成「ros」的最小編輯距離為min(a+1,b+1,c+1)。
所以這道題就可以使用動態規劃的方式來求解。我們假設dp[i] [j] 表示word1的前i個字元,變換到word2的前j個字元的最小編輯距離。根據上面的分析,我們可以知道它是由以下三種狀態轉移的最小值過來的。即
- dp[i] [j] = dp[i] [j-1] +1,即在單詞A中增加一個字元
- dp[i] [j] = dp [i-1] [j] + 1,即在單詞A中刪除一個字元
- dp[i] [j] = dp[i-1] [j-1] +1,即在單詞A中替換一個字元
所以動態轉移方程為:
若A、B的最後一個字元相同 **dp[i] [j] = min(dp[i] [j-1]+1,dp [i-1] [j]+1,dp[i-1] [j-1]) **。
若A、B的最後一個字元不相同 dp[i] [j] = min(dp[i] [j-1]+1,dp [i-1] [j]+1,dp[i-1] [j-1]+1)。
下面我們來看一下邊界情況,一個空串和一個非空串的編輯距離dp[i] [0] = i, dp[0] [j] =j。dp[i] [0] 相當於對word1執行了i次刪除操作,dp[0] [j]相當於對word1進行了j次插入操作。
下面我們來看一下程式碼實現。
class Solution:
def minDistance(self, word1, word2):
#求出單詞的長度
n = len(word1)
m = len(word2)
#判斷是否是空串
if n==0:
return m
if m==0:
return n
#定義狀態轉移矩陣
dp = [[0] * (m + 1) for _ in range(n + 1)]
#處理邊界條件
for i in range(n + 1):
dp[i][0] = i
for j in range(m + 1):
dp[0][j] = j
#填充狀態轉移矩陣
for i in range(1, n + 1):
for j in range(1, m + 1):
#上邊狀態轉移過來
up = dp[i - 1][j] + 1
#左邊狀態轉移過來
left = dp[i][j - 1] + 1
#左上的狀態
left_up = dp[i - 1][j - 1]
#如果最後一個字元不相同,left_up需要加1
if word1[i - 1] != word2[j - 1]:
left_up += 1
dp[i][j] = min(left, up, left_up)
return dp[n][m]
該演算法的時間複雜度和空間複雜度都是O(n*m)。
最後
送大家幾本比較不錯的演算法書籍~
小爭哥數據結構與演算法
鏈接://pan.baidu.com/s/19Jk_G_-QTnGb3GRyzbENgA
密碼:keis
Google大佬LeetCode刷題指南
鏈接://pan.baidu.com/s/1vtRIsVltTxmIioqqkeSS5g
密碼:r3xg
演算法小抄
鏈接://pan.baidu.com/s/1rU_T6GRZ-WmV9QFmnJfCBg
密碼:unh5