【LeetCode】编辑距离 [H](动态规划)
2023-09-27 14:19:52 时间
一、题目
给你两个单词 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
由小写英文字母组成
二、代码
class Solution {
public int minDistance(String word1, String word2) {
if (word1 == null || word2 == null) {
return 0;
}
char[] s1 = word1.toCharArray();
char[] s2 = word2.toCharArray();
// dp[i][j]:s1前缀取前i个字符,编辑成s2前缀取j个字符,将s1的前i个字符组成的前缀串如何用最少编辑代价转换成s2的前j个字符的前缀串,最少代价是多少。
// dp[i][j] = -1表示当前状态下无法编辑成功
int[][] dp = new int[s1.length + 1][s2.length + 1];
// 初始化dp数组 规定dp[0][0] = 0
// 0列s2编辑成s1空串,只能删除
for (int i = 1; i <= s1.length; i++) {
dp[i][0] = 1 * i;
}
// 0行s1空串编辑为s2,只能添加
for (int j = 1; j <= s2.length; j++) {
dp[0][j] = 1 * j;
}
for (int i = 1; i <= s1.length; i++) {
for (int j = 1; j <= s2.length; j++) {
// 分情况讨论
// 可能性1:s1的前i-1个字符可以变成s2的前j个字符,即删掉s1的最后一个i位置的字符即可完成编辑,如果dp[i - 1][j] == -1,说明无法编辑成功,赋值为-1
int p1 = dp[i - 1][j] != -1 ? dp[i - 1][j] + 1 : -1;
// 可能性2:s1的前i个字符先变成str2的前j-1个字符,后再加上s2的最后一个j位置的字符即可完成编辑。如果dp[i][j - 1] == -1,说明无法编辑成功,赋值为-1
int p2 = dp[i][j - 1] != -1 ? dp[i][j - 1] + 1 : -1;
// 可能性3: s1, s2两个字符串最后一个字符串相等,如果str1前面i-1个字符可以编辑成s2前面j-1个字符,那么最后一个字符保留即可完成编辑。
// 可能性4:s1, s2两个字符串最后一个字符串不相等,如果str1前面i-1个字符可以编辑成s2前面j-1个字符,那么最后一个字符替换即可完成编辑。
int p3 = s1[i - 1] == s2[j - 1] ? (dp[i - 1][j - 1] != -1 ? dp[i - 1][j - 1] : -1) : (dp[i - 1][j - 1] != -1 ? dp[i - 1][j - 1] + 1 : -1);
// 取四种情况的最小值
dp[i][j] = Math.min(p1, Math.min(p2, p3));
}
}
// 返回答案
return dp[s1.length][s2.length];
}
}
三、解题思路
道题最大的难点是将所有的可能性都想出来,不能有遗漏。一共有四种可能:
- 可能性1:s1的前i-1个字符可以变成s2的前j个字符,即删掉s1的最后一个i位置的字符即可完成编辑,如果dp[i - 1][j] == -1,说明无法编辑成功,赋值为-1
- 可能性2:s1的前i个字符先变成str2的前j-1个字符,后再加上s2的最后一个j位置的字符即可完成编辑。如果dp[i][j - 1] == -1,说明无法编辑成功,赋值为-1
- 可能性3: s1, s2两个字符串最后一个字符串相等,如果str1前面i-1个字符可以编辑成s2前面j-1个字符,那么最后一个字符保留即可完成编辑。
- 可能性4:s1, s2两个字符串最后一个字符串不相等,如果str1前面i-1个字符可以编辑成s2前面j-1个字符,那么最后一个字符替换即可完成编辑。
相关文章
- 别迷茫了,师兄告诉你怎么刷 LeetCode
- LeetCode——Copy List with Random Pointer
- LeetCode高频题70. 爬楼梯,青蛙跳台阶,暴力递归的尝试,改记忆化搜索和动态规划代码
- LeetCode数据结构_C语言题解系列-数组II&动态规划
- LeetCode动态规划基础题-子字符串问题(13题)
- LeetCode动态规划基础题-股票买卖
- 192、【动态规划】leetcode ——64. 最小路径和:回溯法+动态规划(C++版本)
- 179、【动态规划】leetcode ——115. 不同的子序列(C++版本)
- 174、【动态规划/贪心算法/滑动窗口】leetcode ——674. 最长连续递增序列:一题多解 (C++版本)
- 173、【动态规划】leetcode ——300. 最长递增子序列 (C++版本)
- 168、【动态规划】leetcode ——121. 买卖股票的最佳时机:dp数组+变量优化 (C++版本)
- 164、【动态规划】leetcode ——213. 打家劫舍 II:环形列表线性化(C++版本)
- 158、【动态规划】leetcode ——518. 零钱兑换 II:二维数组+一维滚动数组(C++版本)
- 155、【动态规划】leetcode ——474. 一和零:三维数组+二维滚动数组(C++版本)
- 148、【动态规划】leetcode ——63. 不同路径 II:递归法+迭代法(C++版本)
- 147、【动态规划】leetcode ——62. 不同路径:递归法+迭代法(C++版本)
- 145、【动态规划】leetcode ——70. 爬楼梯:暴力法+动态规划(C++版本)