leetcode 583. 两个字符串的删除操作
题目链接:583. 两个字符串的删除操作 - 力扣(LeetCode)
视频链接:动态规划之子序列,还是为了编辑距离做铺垫 | LeetCode:583.两个字符串的删除操作_哔哩哔哩_bilibili
题目概述
给定两个单词
word1
和word2
,返回使得word1
和word2
相同所需的最小步数。每步 可以删除任意一个字符串中的一个字符。
示例 1:
输入: word1 = "sea", word2 = "eat" 输出: 2 解释: 第一步将 "sea" 变为 "ea" ,第二步将 "eat "变为 "ea"
示例 2:
输入:word1 = "leetcode", word2 = "etco" 输出:4
1.确定dp数组含义
dp[i][j]:以i-1为结尾的字符串word1,和以j-1位结尾的字符串word2,想要达到相等,所需要删除元素的最少次数
2.确定递推公式
1)word1[i - 1] 等于 word2[j - 1]:
dp[i][j] = dp[i - 1][j - 1]
2)word1[i - 1] 不等于 word2[j - 1]:
dp[i - 1][j] + 1(删除word1)
dp[i][j - 1] + 1(删除word2)
dp[i - 1][j - 1] + 2(删除word1和word2)
所以dp[i][j] = min({dp[i - 1][j - 1] + 2, dp[i - 1][j] + 1, dp[i][j - 1] + 1})
3.数组初始化
dp[i][0] = i(word2为空字符串,以i-1为结尾的字符串word1要删除i个元素,才能和word2相同)
dp[0][j] = j(word1为空字符串,以j-1为结尾的字符串word2要删除j个元素,才能和word1相同)
4.确定遍历顺序
dp[i][j]可以由左边、上边、左上方推导而来,所以遍历顺序是从左到右、从上到下。
5.打印dp数组
class Solution {
public:
int minDistance(string word1, string word2) {
vector> dp(word1.size() + 1,vector(word2.size() + 1));
for(int i = 0;i <= word1.size();i++) dp[i][0] = i;
for(int j = 0;j <= word2.size();j++) dp[0][j] = j;
for(int i = 1;i <= word1.size();i++) {
for(int j = 1;j <= word2.size();j++) {
if(word1[i - 1] == word2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1];
}
else {
dp[i][j] = min({dp[i][j - 1] + 1,dp[i - 1][j] + 1,dp[i - 1][j - 1] + 2});
}
}
}
return dp[word1.size()][word2.size()];
}
};
第二种方法:
可以把两个字符串的最长公共子序列求出来,然后用两个字符串加一起的长度 减去 最长公共子序列的长度*2 就可以了。
class Solution {
public:
int minDistance(string word1, string word2) {
vector> dp(word1.size()+1, vector(word2.size()+1, 0));
for (int i=1; i<=word1.size(); i++){
for (int j=1; j<=word2.size(); j++){
if (word1[i-1] == word2[j-1]) dp[i][j] = dp[i-1][j-1] + 1;
else dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
}
}
return word1.size()+word2.size()-dp[word1.size()][word2.size()]*2;
}
};
leetcode 72. 编辑距离
题目链接:72. 编辑距离 - 力扣(LeetCode)
视频链接:动态规划之子序列,还是为了编辑距离做铺垫 | LeetCode:583.两个字符串的删除操作_哔哩哔哩_bilibili
编辑距离是用动规来解决的经典题目,前面的几道题都是为了这道题做铺垫!
题目概述
给你两个单词
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数组的含义
dp[i][j] 表示以下标i-1为结尾的字符串word1,和以下标j-1为结尾的字符串word2,最近编辑距离为dp[i][j]。
2.确定递推公式
当word1[i - 1] == word2[j - 1])时:
dp[i][j] = dp[i - 1][j - 1]
当word1[i - 1] != word2[j - 1])时
:(有增、删、替换 三种操作)
dp[i][j] = dp[i - 1][j] + 1(
word1删除一个元素)
dp[i][j] = dp[i][j - 1] + 1(
word2删除一个元素)
(word2添加一个元素,相当于word1删除一个元素,例如 word1 = "ab",word2 = "a"
,word1
删除元素'b'
和word2
添加一个元素'b'
,变成word1="a", word2="ab"
, 最终的操作数是一样的)
dp[i][j] = dp[i - 1][j - 1] + 1;
(
替换元素)
所以
dp[i][j] = min({dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]}) + 1;
3.数组初始化
dp[0][j] = j
dp[i][0] = i
4.确定遍历顺序
由上图可以看出:dp[i][j]可以由 左边、上边、左上方推出,所以遍历顺序为从左到右,从上到下。
5.打印dp数组(以输入:word1 = "horse", word2 = "ros"
为例)
lass Solution {
public:
int minDistance(string word1, string word2) {
vector> dp(word1.size() + 1,vector(word2.size() + 1,0));
for(int i = 0;i <= word1.size();i++) dp[i][0] = i;
for(int j = 0;j <= word2.size();j++) dp[0][j] = j;
for(int i = 1;i <= word1.size();i++) {
for(int j = 1;j <= word2.size();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] + 1,dp[i][j - 1] + 1,dp[i - 1][j - 1] + 1});
}
}
}
return dp[word1.size()][word2.size()];
}
};