72. Edit Distance
现有word1,word2两个字符串,每次对word1可以执行如下3中操作之一:
1,插入一个字母;2,删除一个字母;3,改变一个字母
问从word1变到word2至少要多少步,
72. Edit Distance Hard 1606 20 Favorite Share Given two words word1 and word2, find the minimum number of operations required to convert word1 to word2. You have the following 3 operations permitted on a word: Insert a character Delete a character Replace a character Example 1: Input: word1 = "horse", word2 = "ros" Output: 3 Explanation: horse -> rorse (replace 'h' with 'r') rorse -> rose (remove 'r') rose -> ros (remove 'e') Example 2: Input: word1 = "intention", word2 = "execution" Output: 5 Explanation: intention -> inention (remove 't') inention -> enention (replace 'i' with 'e') enention -> exention (replace 'n' with 'x') exention -> exection (replace 'n' with 'c') exection -> execution (insert 'u')
我的思路:
f(i,j)表示word1的前i个数字变为word2的前j个数字的步数;
如果最后一个数相同,那么f(i,j) = f(i-1,j-1);
如果不同的话,分为三种可能:
1,word1最后一个字母变为word2最后一个字母:f(i,j)=f(i-1,j-1)+1;
2,word1最后一个字母删去:f(i,j)=f(i-1,j)+1;
3,word1在最后插入word2最后一个字母,这就等效于word2最后一个字母删去:f(i,j)=f(i,j-1)+1;
下面是我的代码
class Solution: def minDistance(self, word1, word2): """ :type word1: str :type word2: str :rtype: int """ len1, len2 = len(word1), len(word2) #(i,j)代表word1前i个字母到word2前j个字母需要的步数 resultmartix = [[None for j in range(len2+1)]for i in range(len1+1)] resultmartix[0][0] = 0 for i in range(1, len1+1): resultmartix[i][0] = i for j in range(1, len2+1): resultmartix[0][j] = j for i in range(1, len1+1): for j in range(1, len2+1): if word1[i-1] == word2[j-1]: resultmartix[i][j] = resultmartix[i-1][j-1] else: resultmartix[i][j] = min(resultmartix[i-1][j-1], resultmartix[i-1][j], resultmartix[i][j-1]) + 1 return resultmartix[len1][len2]
看到一个很快的解法:
class Solution: def minDistance(self, word1, word2): """ :type word1: str :type word2: str :rtype: int """ import heapq heap = [(0, word1, word2)] # initialize, at first we don't know how manys steps it will take to convert word1 to word2 (0) visited = set() while heap: # use min-heap to always pick the triplet with the current minimum distance (the most promising) distance, w1, w2 = heapq.heappop(heap) # no duplication computation !!! if (w1,w2) in visited: continue visited.add((w1,w2)) # if what's left are equal(or both none), then we have found the answer if w1 == w2: return distance if w1 and w2 and w1[-1] == w2[-1]: # the last char match, distance unchanged heapq.heappush(heap, (distance, w1[:-1], w2[:-1])) else: # we should choose from those 3 ops to make these two match, steps++ # remove if w1: heapq.heappush(heap, (distance + 1, w1[:-1], w2)) # replace if w1 and w2: heapq.heappush(heap, (distance + 1, w1[:-1], w2[:-1])) # insert if w2: heapq.heappush(heap, (distance + 1, w1, w2[:-1]))
用了逆向的想法,我们的想法是从空字符串到word1,word2要多少步,而这个方法就是word1,word2变为两个相同的字符串要多少步
其中用到了最小堆,其实可以不必如此,我仿照这样的思路写了一个不用最小堆的方法,也就是广度优先搜索:
class Solution: def minDistance(self, word1, word2): """ :type word1: str :type word2: str :rtype: int """ if word1 == word2: return 0 len1, len2 = len(word1), len(word2) #(i,j)代表word1前i个字母和word2前j个字母到word1,word2要的步数 resultmartix = [[None for j in range(len2+1)]for i in range(len1+1)] resultmartix[len1][len2] = 0 queue = [(len1, len2)] time = 0 while 1: tmp = [] if resultmartix[0][0] != None: return resultmartix[0][0] for i, j in queue: while i and j and word1[i-1] == word2[j-1]: resultmartix[i-1][j-1] = time i, j = i-1, j-1 if i and resultmartix[i-1][j] == None: resultmartix[i-1][j] = time + 1 tmp.append((i-1, j)) if j and resultmartix[i][j-1] == None: resultmartix[i][j-1] = time + 1 tmp.append((i, j-1)) if i and j and resultmartix[i-1][j-1] == None: resultmartix[i-1][j-1] = time + 1 tmp.append((i-1, j-1)) time += 1 queue = tmp