题目描述:
2.判断子序列
3.两个字符串的删除操作
思路
这三道题其实都是一类题:操作字符串 使得两个字符串相等或者使得一个为另一个的子字符串,判断子序列可以通过判断两个字符串的最长子序列长度是否和短的那个相等.
下面我们着重讲解一下编辑距离这道题目:
1)规定dp[i][j]表示使得t[0,i-1]到t[0,j-1]相等的最少操作次数
2)递推公式:如果s[i]==t[j],说明不需要操作,dp[i][j]==dp[i-1][j-1],如果不相等的话,我们有三种选择:
删除其中一个,删除另一个,更换一个(为什么没有增加呢?因为一个字符串的增加就意味着另一个字符串的减少,也就说,增加是不必要的)
dp[i][j]=min(dp[i-1][j],dp[i][j-1],dp[i-1][j-1])+1;
3)初始化:dp[0][i]=i dp[0][i]=i ,i从1开始,因为[0,i-1]一共要操作i次
4)递推顺序:由公式可知,从左上到右下角.
5)手动演算(略)
代码--编辑距离
class Solution {
public:
int minDistance(string word1, string word2) {
int size1 = word1.size();
int size2 = word2.size();
vector<vector<int>> dp(size1 + 1, vector<int>(size2 + 1, 0));
for (int i = 1; i <= size1; ++i) dp[i][0] = i; //word2为空字符串,word1要删除多少个才是空字符串
for (int i = 1; i <= size2; ++i) dp[0][i] = i;
for (int i = 1; i <= size1; ++i) {
for (int j = 1; j <= size2; ++j) {
if (word1[i - 1] == word2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1];
}
else dp[i][j] = min(min(dp[i - 1][j] + 1, dp[i][j - 1] + 1), dp[i - 1][j - 1] + 1);
}
}
return dp[size1][size2];
}
};
字符串删除:
class Solution {
public:
int minDistance(string word1, string word2) {
int size1 = word1.size() ;
int size2 = word2.size() ;
vector<vector<int>> dp(size1 + 1, vector<int>(size2 + 1,0));
for (int i = 1; i <= size1; ++i) dp[i][0] = i; //word2为空字符串,word1要删除多少个才是空字符串
for (int i = 1; i <= size2; ++i) dp[0][i] = i;
for (int i = 1; i <= size1; ++i) {
for (int j = 1; j <= size2; ++j) {
if (word1[i-1] == word2[j-1]) {
dp[i][j] = dp[i - 1][j - 1];
}
else dp[i][j] = min(min(dp[i - 1][j]+1, dp[i][j - 1]+1),dp[i-1][j-1]+2) ;
}
}
return dp[size1][size2];
}
};
判断子序列:
class Solution {
public:
bool isSubsequence(string s, string t) { //s是不是t的子序列
int size1 = s.size(), size2 = t.size();
if (size1 == 0) return true;
if (size2 == 0) return false;
vector<vector<int>> dp(size1 + 1, vector<int>(size2 + 1, 0));
for (int i = 1; i <= size1; ++i) {
for (int j = 1; j <= size2; ++j) {
if (s[i - 1] == t[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
}
else dp[i][j] = dp[i][j - 1];
}
}
return dp[size1][size2] == size1 ? true : false;
}
};