题目描述
给你两个单词 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’)
提示:
0 <= word1.length, word2.length <= 500
word1 和 word2 由小写英文字母组成
思路
单词转换问题,也称为编辑距离问题,可以使用动态规划来解决。下面我将详细解释解题思路,并提供关键算法和算法思想的说明。
解题思路:
这个问题可以使用动态规划来解决,动态规划是一种用于求解最优化问题的算法思想。我们可以通过构建一个二维数组 dp
来记录从 word1
的前缀变换到 word2
的前缀所需要的最小操作数。
假设 dp[i][j]
表示将 word1
的前 i
个字符变换为 word2
的前 j
个字符所需的最小操作数。那么,我们可以进行以下操作:
- 如果
word1[i-1]
等于word2[j-1]
,则不需要进行操作,即dp[i][j] = dp[i-1][j-1]
。 - 否则,我们可以进行三种操作中的一种:
- 插入操作:
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[word1.length][word2.length]
即为我们所求的结果,即将整个 word1
转换为 word2
所需的最小操作数。
关键算法和算法思想:
动态规划的关键在于构建状态转移方程,并通过子问题的解来求解大问题的解。在这个问题中,我们使用二维数组 dp[i][j]
来记录转换状态。对于每个位置 (i, j)
,我们需要根据其前一个状态 (i-1, j)
、(i, j-1)
和 (i-1, j-1)
的值来计算。
状态转移方程为:
dp[i][j] = min(dp[i-1][j] + 1, dp[i][j-1] + 1, dp[i-1][j-1] + (word1[i-1] != word2[j-1] ? 1 : 0))
其中,dp[i-1][j] + 1
表示删除操作,dp[i][j-1] + 1
表示插入操作,dp[i-1][j-1] + (word1[i-1] != word2[j-1] ? 1 : 0)
表示替换操作。
通过填充 dp
数组,我们最终可以得到将 word1
转换为 word2
所需的最小操作数。
代码
object Solution {
def minDistance(word1: String, word2: String): Int = {
val m = word1.length
val n = word2.length
val dp = Array.ofDim[Int](m + 1, n + 1)
for (i <- 0 to m) dp(i)(0) = i
for (j <- 0 to n) dp(0)(j) = j
for (i <- 1 to m) {
for (j <- 1 to n) {
val insert = dp(i)(j - 1) + 1
val delete = dp(i - 1)(j) + 1
val replace = dp(i - 1)(j - 1) + (if (word1(i - 1) == word2(j - 1)) 0 else 1)
dp(i)(j) = Math.min(Math.min(insert, delete), replace)
}
}
dp(m)(n)
}
}