问题72:给定两个单词word1和word2,求出将word1转换成word2所使用的最少操作数。
你可以对一个单词进行如下三种操作:
- 插入一个字符
- 删除一个字符
- 替换一个字符

这题再一次展示了动态规划的强大。看上去毫无头绪的问题,用动态规划方法可以轻松解决。

定义一个len(word1)*len(word2)的二维数组dp,其中第i行第j列dp[i][j]表示将word1的前i个字符转换为word2的前j个字符需要的最少操作数。
初始化条件:dp[i][0] = i,dp[0][j] = j,这个很显然,把一个长度为i的单词转换为长度为0的单词需要删除i次,把一个长度为0的单词转换为长度为j的单词需要插入j次。
状态转移方程:本题状态转移方程为重点,共有四种情况。
- 情况一:通过插入一个字符,使得
word1和word2相同。dp[i][j] = dp[i][j-1] + 1。意思是,如果我们能把word1的前i个字符转换为word2的前j-1个字符,那么我们只需要在其基础上对word1进行一步插入操作,就可以把word1的前i个字符转换为word2的前j个字符。

- 情况二;通过删除一个字符,使得
word1和word2相同。dp[i][j] = dp[i-1][j] + 1。意思是,如果我们能把word1的前i-1个字符转换为word2的前j个字符,那么我们只需要在其基础上对word1进行一步删除操作,就可以把word1的前i个字符转换为word2的前j个字符。

- 情况三:通过替换一个字符,使得
word1和word2相同。dp[i][j] = dp[i-1][j-1] + 1。意思是,如果我们能把word1的前i-1个字符转换为word2的前j-1个字符,那么我们只需要在其基础上对word1进行一步替换操作,把word1[i]换成word2[j],就可以把word1的前i个字符转换为word2的前j个字符。

- 情况四:贪心情况。如果
word1[i] = word2[j],则dp[i][j] = dp[i-1][j-1] + 1。意思是,如果word1的第i个字符和word2的第j个字符相同,则如果我们能把word1的前i-1个字符转换为word2的前j-1个字符,那么我们什么也不用干,就可以把word1的前i个字符转换为word2的前j个字符。
完整代码:
class Solution:
def minDistance(self, word1: str, word2: str) -> int:
dp = [[None for _ in range(len(word2)+1)] for _ in range(len(word1)+1)]
for i in range(len(word1)+1):
dp[i][0] = i
for j in range(1, len(word2)+1):
dp[0][j] = j
for i in range(1, len(word1)+1):
for j in range(1, len(word2)+1):
if word1[i-1] == word2[j-1]:
dp[i][j] = dp[i-1][j-1]
else:
dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1
return dp[len(word1)][len(word2)]
运行结果:
