1. 程式人生 > >編輯距離問題——python動態規劃解法

編輯距離問題——python動態規劃解法

問題:

給定兩個單詞 word1 和 word2,計算出將 word1 轉換成 word2 所使用的最少運算元 。

你可以對一個單詞進行如下三種操作:

  1. 插入一個字元
  2. 刪除一個字元
  3. 替換一個字元

示例 1:

輸入: word1 = "horse", word2 = "ros"
輸出: 3
解釋: 
horse -> rorse (將 'h' 替換為 'r')
rorse -> rose (刪除 'r')
rose -> ros (刪除 'e')

示例 2:

輸入: word1 = "intention", word2 = "execution"
輸出: 5
解釋: 
intention -> inention (刪除 't')
inention -> enention (將 'i' 替換為 'e')
enention -> exention (將 'n' 替換為 'x')
exention -> exection (將 'n' 替換為 'c')
exection -> execution (插入 'u')

(此題目摘自leetcode)

前面說過,動態規劃的思路是為了求解當前的問題的最優解,使用子問題的最優解,然後綜合處理,最終得到原問題的最優解。那麼我們要求出word1轉化為word2的最少運算元,就把兩個字串一步步拆解開來,求出每一步的最少運算元,得到最優解。

下面以單詞apple和orange舉例說明


如圖,null代表空字元(為什麼要加空字元之後會說到),orange之所以由下而上寫是因為這樣可以跟直角座標系對應起來,便於理解。假設圖中以0所在位置為座標原點,那麼(0,0)代表的意義就是將null轉化為null的最少運算元(理所當然為0),(1,0)代表的意義是將a轉化為null的最少運算元,(0,6)代表的意義是將null轉化為orange的最少運算元,等等。這裡就體現了引入null(即空字元)的意義,題目中所能做的操作有插入,刪除,替換,把字元轉化為null就代表刪除操作,把null轉化為字元就代表插入操作,這樣就把插入和刪除這樣抽象的狀態以具象形式表達了出來。

那麼如何求得座標(1,1)(即將a轉化為o的最少運算元)的值呢?

可以以三種操作來做。從(1,0)到(1,1),意義就是將a先刪除,然後再插入o,也就是在(1,0)的基礎上再加了一步插入操作,所以這個運算元為1+1=2;從(0,1)到(1,1),意義就是先插入o,再刪除a,也就是在(0,1)的基礎上再加了一步刪除操作,所以這個運算元為1+1=2;從(0,0)到(1,1),則是當a和o兩個字串前面都已經完全相同時,做的替換操作,而在這裡a!=o,所以所以這個運算元為0+1=1。在三者中取最小值,即為座標(1,1)的值,為1。


補一張圖幫助理解。

所以在這個例子中,此題的最優解,就變成了求座標(5,6)的值。從(1,1)開始,一步一步求出最終解,這樣程式設計思路就非常清晰了。建立二維陣列target[i][j]就可以輕鬆實現。此例子最終結果為:


所以將apple轉化為orange所需的最少運算元為5,具體過程:apple>opple>orpple>oraple>oranle>orange(非唯一)

以下是程式碼實現:

class Solution(object):

def minDistance(self, word1, word2):
"""
:type word1: str
:type word2: str
:rtype: int
"""
word1 = ' ' + word1
word2 = ' ' + word2
target = [['' for j in range(len(word2))] for i in range(len(word1))]
for i in range(len(word1)):
target[i][0] = i 
for j in range(len(word2)):
target[0][j] = j 
for i in range(1, len(word1)):
for j in range(1, len(word2)):
if word1[i] != word2[j]:
target[i][j] = min(target[i - 1][j] + 1, target[i][j - 1] + 1, target[i - 1][j - 1] + 1)
else:
target[i][j] = min(target[i - 1][j] + 1, target[i][j - 1] + 1, target[i - 1][j - 1])
#print('target[%d][%d]'%(i, j),target[i][j])

return target[len(word1) - 1][len(word2) - 1]

繼昨天剛開始理解動態規劃,今天就又開始頭皮發麻,願能給同樣雲裡霧裡的小夥伴們一點幫助