一、问题描述
- 两个字符串的删除操作
给定两个单词 word1 和 word2,请找到使得 word1 和 word2 相同所需的最小步数,每步可以删除任意一个字符串中的一个字符。
示例:
输入: "sea", "eat" 输出: 2 解释: 第一步将"sea"变为"ea",第二步将"eat"变为"ea"
- 编辑距离
给定两个单词 word1 和 word2,请计算出将 word1 转换成 word2 所使用的最少操作数。
你可以对一个单词进行如下三种操作:
插入一个字符 删除一个字符 替换一个字符
示例:
输入: word1 = "horse", word2 = "ros" 输出: 3 解释: horse -> rorse (将 'h' 替换为 'r') rorse -> rose (删除 'r') rose -> ros (删除 'e')
二、动态规划解法
- 两个字符串的删除操作
定义状态:
dp[i][j] 表示 word1 的前 i 个字符和 word2 的前 j 个字符的最少删除次数。
转移方程:
当 word1[i-1] == word2[j-1] 时,dp[i][j] = dp[i-1][j-1];
当 word1[i-1] != word2[j-1] 时,dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + 1。
初始状态:
dp[0][j] = j,表示将 word2 的前 j 个字符全部删除;
dp[i][0] = i,表示将 word1 的前 i 个字符全部删除。
最终答案:
dp[m][n],其中 m 和 n 分别为 word1 和 word2 的长度。
Java 代码实现:
class Solution {
public int minDistance(String word1, String word2) {
int m = word1.length(), n = word2.length();
int[][] dp = new int[m+1][n+1];
for (int i = 0; i <= m; i++) {
dp[i][0] = i;
}
for (int j = 0; j <= n; j++) {
dp[0][j] = j;
}
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (word1.charAt(i-1) == word2.charAt(j-1)) {
dp[i][j] = dp[i-1][j-1];
} else {
dp[i][j] = Math.min(dp[i-1][j], dp[i][j-1]) + 1;
}
}
}
return dp[m][n];
}
}
- 编辑距离
定义状态:
dp[i][j] 表示 word1 的前 i 个字符和 word2 的前 j 个字符的最少编辑距离。
转移方程:
当 word1[i-1] == word2[j-1] 时,dp[i][j] = dp[i-1][j-1];
当 word1[i-1] != word2[j-1] 时,dp[i][j] = min(dp[i-1][j-1], dp[i-1][j], dp[i][j-1]) + 1。
其中,dp[i-1][j-1] 表示替换操作,dp[i-1][j] 表示删除操作,dp[i][j-1] 表示插入操作。
初始状态:
dp[0][j] = j,表示将 word2 的前 j 个字符全部插入;
dp[i][0] = i,表示将 word1 的前 i 个字符全部删除。
最终答案:
dp[m][n],其中 m 和 n 分别为 word1 和 word2 的长度。
Java 代码实现:
class Solution {
public int minDistance(String word1, String word2) {
int m = word1.length(), n = word2.length();
int[][] dp = new int[m+1][n+1];
for (int i = 0; i <= m; i++) {
dp[i][0] = i;
}
for (int j = 0; j <= n; j++) {
dp[0][j] = j;
}
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (word1.charAt(i-1) == word2.charAt(j-1)) {
dp[i][j] = dp[i-1][j-1];
} else {
dp[i][j] = Math.min(dp[i-1][j-1], Math.min(dp[i-1][j], dp[i][j-1])) + 1;
}
}
}
return dp[m][n];
}
}
三、技术报告
动态规划是一种非常重要的算法思想,它已经被广泛应用在各种领域中。动态规划的基本思想是将问题分解为子问题,通过求解子问题来解决原问题,从而避免了重复计算,提高了算法效率。
本文介绍了两个字符串相关的动态规划问题:两个字符串的删除操作和编辑距离。这两个问题都可以通过动态规划来解决,其中最重要的一步是定义状态以及状态转移方程。
在两个字符串的删除操作中,我们定义状态 dp[i][j] 表示 word1 的前 i 个字符和 word2 的前 j 个字符的最少删除次数。当 word1[i-1] == word2[j-1] 时,dp[i][j] = dp[i-1][j-1];当 word1[i-1] != word2[j-1] 时,dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + 1。初始状态为 dp[0][j] = j 和 dp[i][0] = i,最终答案为 dp[m][n],其中 m 和 n 分别为 word1 和 word2 的长度。
在编辑距离问题中,我们定义状态 dp[i][j] 表示 word1 的前 i 个字符和 word2 的前 j 个字符的最少编辑距离。当 word1[i-1] == word2[j-1] 时,dp[i][j] = dp[i-1][j-1];当 word1[i-1] != word2[j-1] 时,dp[i][j] = min(dp[i-1][j-1], dp[i-1][j], dp[i][j-1]) + 1。初始状态和最终答案的定义与两个字符串的删除操作相同。
以上两个问题的动态规划解法都具有时间复杂度 O(mn) 和空间复杂度 O(mn),其中 m 和 n 分别为两个字符串的长度。在实际应用中,我们可以通过优化空间复杂度来进一步提高算法效率。