问题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)]
运行结果: