一、问题描述
给你两个单词 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')
二、方案一:动态规划
1、思路
动态规划是解决此类问题的常用方法。我们定义一个二维数组 dp[i][j]
表示将 word1
的前 i
个字符转换为 word2
的前 j
个字符所需的最少操作数。
- 如果
word1[i] == word2[j]
,那么dp[i][j] = dp[i-1][j-1]
。 - 如果
word1[i] != word2[j]
,那么dp[i][j]
可以通过以下三种操作之一得到:- 插入:
dp[i][j] = dp[i][j-1] + 1
- 删除:
dp[i][j] = dp[i-1][j] + 1
- 替换:
dp[i][j] = dp[i-1][j-1] + 1
- 插入:
- 我们需要初始化
dp
数组,dp[i][0]
和dp[0][j]
分别表示将word1
的前i
个字符转换为空字符串和将空字符串转换为word2
的前j
个字符所需的操作数。
2、代码实现
go
func minDistance(word1 string, word2 string) int {
m, n := len(word1), len(word2)
dp := make([][]int, m+1)
for i := range dp {
dp[i] = make([]int, n+1)
}
// 初始化 dp 数组
for i := 0; i <= m; i++ {
dp[i][0] = i
}
for j := 0; j <= n; j++ {
dp[0][j] = j
}
// 填充 dp 数组
for i := 1; i <= m; i++ {
for j := 1; j <= n; j++ {
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[m][n]
}
func min(a, b, c int) int {
if a < b {
if a < c {
return a
}
return c
}
if b < c {
return b
}
return c
}
3、复杂度分析
- 时间复杂度:O(m×n),其中 m 和 n 分别是字符串
word1
和word2
的长度。我们需要填充一个 m×n 的二维数组。 - 空间复杂度:O(m×n),我们需要一个 m×n 的二维数组来存储中间结果。
三、方案二:递归 + 记忆化搜索
1、思路
我们可以使用递归的方法来解决这个问题。对于字符串 word1
和 word2
的任意两个位置 i
和 j
,如果 word1[i] == word2[j]
,那么 dp[i][j] = dp[i-1][j-1]
;否则,dp[i][j] = min(dp[i][j-1], dp[i-1][j], dp[i-1][j-1]) + 1
。为了避免重复