题目描述
583. 两个字符串的删除操作
给定两个单词 word1 和 word2,找到使得 word1 和 word2 相同所需的最小步数,每步可以删除任意一个字符串中的一个字符。
示例:
输入: "sea", "eat"
输出: 2
解释: 第一步将"sea"变为"ea",第二步将"eat"变为"ea"
提示:
给定单词的长度不超过500。
给定单词中的字符只含有小写字母。
算法
(动态规划)
这题目要先转换成求最大公共子序列问题,然后求结果:
最小需要删除的数字 = word1长度-最长公共子序列长度 + word2长度-最长公共子序列长度
那么问题就变成求最大公共子序列问题,属于模版题:
- dp(i)(j) 表示第一个字符串的前 i 个字符和第二个字符串的前 j个字符的最长公共子序列长度(最后一个字符i,j不一定必选)。
- 初始时 dp(0, j) = dp(i, 0) = 0, dp(0, j) = dp(i, 0) = 0,表示空串不和任何字符串有公共子序列。
- 转移计算:如果 word1(i) == word2(j): dp(i)(j) = dp(i - 1)(j - 1) + 1; 表示既可以忽略 word1(i)和word(j),因为他们必然相同。否则,dp(i,j)=max(dp(i−1,j), dp(i,j−1)),表示只能忽视word1(i) 或忽视word2(j)。
- 最大公共子序列问题答案dp(n1,n2)。
时间复杂度 O(n1*n2)
Java 代码
class Solution {
public int minDistance(String word1, String word2) {
// 这题目其实就是最长公共子序列
int n1 = word1.length();
int n2 = word2.length();
// dp[i][j] word1前i 与 word2前j组成的的最长公共子序列的长度,i,j不一定必选
int[][] dp = new int[n1 + 1][n2 + 1];
for (int i = 0; i <= n1; i++) {
for (int j = 0; j <= n2; j++) {
if (i == 0 || j == 0) {
dp[i][j] = 0;
continue;
}
if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
// 需要删除的数字 = word1长度-最长公共子序列长度 + word2长度-最长公共子序列长度
return n1 - dp[n1][n2] + n2 - dp[n1][n2];
}
}