Leetcode 72:編輯距離(超詳細的解法!!!)
給定兩個單詞 word1 和 word2,計算出將 word1 轉換成 word2 所使用的最少運算元 。
你可以對一個單詞進行如下三種操作:
- 插入一個字元
- 刪除一個字元
- 替換一個字元
示例 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')
解題思路
這個問題非常簡單,有點類似於LCS問題,所以我們很容易想到通過動態規劃來求解這個問題。我們首先思考一下遞迴過程。我們通過兩個指標i
和j
分別指向word1
和word2
。我們定義函式
表示word1[:i]
轉換為word2[:j]
需要的最少步驟。
word1: h o r s e
i
word2: r o s
j
我們首先要比較word1[i-1]
和word2[j-1]
是不是相同,如果相同的話,我們就不用做任何操作,所以此時
(i
和j
都向前挪一個位置)。
接著對於不相同的時候我們的情況比較複雜,我們有三種處理手段,分別是insert
、replace
和remove
。我們先看insert
操作。我們insert
完之後,也就是word1
會中的元素會保持不變,而j
會向前挪一個位置,也就是
。接著考慮replace
操作,replace
會減少word1
和word2
中一個需要比較的元素(i
和j
會向前挪一個位置),也就是
。我們接著考慮最後一個remove
操作,這個就很容易了,word1
中會減少一個需要比較的元素,而我們j
的位置不變,也就是
。所以我們最後的結果相當三者取最小值即可。
接著我們要考慮初始條件,也就是word1
和word2
為空的情況,此時也非常簡單
、
。所以我們最後的程式碼也就很容易了
class Solution:
def minDistance(self, word1, word2):
"""
:type word1: str
:type word2: str
:rtype: int
"""
word1_len, word2_len = len(word1), len(word2)
mem = [[0]*(word2_len+1) for _ in range(word1_len+1)]
for i in range(1, word1_len+1):
mem[i][0] = i
for j in range(1, word2_len+1):
mem[0][j] = j
for i in range(1, word1_len+1):
for j in range(1, word2_len+1):
mem[i][j] = min(mem[i-1][j-1]+(word1[i-1]!=word2[j-1]), mem[i][j-1]+1, mem[i-1][j]+1)
return mem[-1][-1]
這個問題可以使用滾動陣列將空間複雜度優化為O(n)
級別,但其實陣列開闢空間和賦值操作也就同樣的增加了時間損耗。
由於問題是求最少運算元,所以我們很容易想到通過廣度優先遍歷來解。只是這裡的廣度優先遍歷和以往的有些區別,我們每次需要訪問的邊有四種。也就是前文說的word1[i-1]==word2[j-1]
的一種情況和word1[i-1]!=word2[j-1]
的三種情況。實際的操作過程非常容易,程式碼如下
from heapq import heappush, heappop
class Solution:
def minDistance(self, word1, word2):
"""
:type word1: str
:type word2: str
:rtype: int
"""
heap = [(0, word1, word2)]
visited = set()
while heap:
d, w1, w2 = heappop(heap)
if (w1, w2) in visited:
continue
visited.add((w1, w2))
if w1 == w2:
return d
if w1 and w2 and w1[0] == w2[0]:
heappush(heap, (d, w1[1:], w2[1:]))
else:
if w1:
heappush(heap, (d+1, w1[1:], w2)) #delete
if w1 and w2:
heappush(heap, (d+1, w1[1:], w2[1:])) #replace
if w2:
heappush(heap, (d+1, w1, w2[1:])) #add
實際的程式碼測試中,使用這種方式實現的程式碼要比前面使用動態規劃完成的速度快。
我將該問題的其他語言版本新增到了我的GitHub Leetcode
如有問題,希望大家指出!!!