给定两个单词 word1 和 word2,计算出将 word1 转换成 word2 所使用的最少操作数 。
你可以对一个单词进行如下三种操作:
插入一个字符
删除一个字符
替换一个字符
代码实现:
1 # 编辑距离 2 class Solution: 3 def minDistance(self, word1: str, word2: str) -> int: 4 m = len(word2) 5 n = len(word1) 6 mem = [[0 for col in range(m + 1)] for row in range(n + 1)] 7 for i in range(n + 1): 8 mem[i][0] = i 9 mem[0] = [i for i in range(m+1)] 10 for row in range(1, n+1): 11 for col in range(1, m+1): 12 if word1[row-1] == word2[col-1]: 13 mem[row][col] = 1 + min(mem[row-1][col], mem[row][col-1],mem[row-1][col-1]-1) 14 else: 15 mem[row][col] = 1 + min(mem[row-1][col], mem[row][col-1],mem[row-1][col-1]) 16 return mem[-1][-1]
算法原理:
蓝色边界:列为word1子序列转换为空所需要的操作次数;行为空序列转换为word2的子序列需要的次数;
计算步骤:
算法思想:
红色部分注意,min函数里面最后一项减去了1;为什么要这样操作呢?这是因为在等式的右边第一项就是1,而这个1表示不管min函数取到什么都要进行一次操作:当取到mem[i-1,j]表示要删除word1中新加入的字符mem[i-1,j]已经可以将子序列转化为word2的目标子序列;当取mem[i,j-1]时,则为插入一个word2新加入子序列的字符;当取mem[i-1,j-1]时,可以将word1加入的元素替换为word2加入的元素。三种情况都是一步操作得到mem[i,j],但是我们应该注意到两个单词新加入的字符不会影响删除和插入操作,对替换却有很大的影响,若两个字符相同,我们根本不需要替换操作,所以当两个字符相同时,mem[i-1,j-1]要先减去1,因为在前面为了形式统一已经加过1了。
动态规划的解法
1 # 基于动态规划的解法 2 def edit_dist(str1, str2): 3 4 # m,n分别字符串str1和str2的长度 5 m, n = len(str1), len(str2) 6 7 # 构建二位数组来存储子问题(sub-problem)的答案 8 dp = [[0 for x in range(n+1)] for x in range(m+1)] 9 10 # 利用动态规划算法,填充数组 11 for i in range(m+1): 12 for j in range(n+1): 13 14 # 假设第一个字符串为空,则转换的代价为j (j次的插入) 15 if i == 0: 16 dp[i][j] = j 17 18 # 同样的,假设第二个字符串为空,则转换的代价为i (i次的插入) 19 elif j == 0: 20 dp[i][j] = i 21 22 # 如果最后一个字符相等,就不会产生代价 23 elif str1[i-1] == str2[j-1]: 24 dp[i][j] = dp[i-1][j-1] 25 26 # 如果最后一个字符不一样,则考虑多种可能性,并且选择其中最小的值 27 else: 28 dp[i][j] = 1 + min(dp[i][j-1], # Insert 29 dp[i-1][j], # Remove 30 dp[i-1][j-1]) # Replace 31 32 return dp[m][n]