LeetCode 392 判断子序列
题目链接:https://leetcode.cn/problems/is-subsequence/
思路:
-
dp数组的含义
dp[i][j]代表以i-1结尾的s子串和以j-1结尾的t子串,相同子序列的长度 -
递推公式
本题有两种情况:
1、s[i - 1] == t[j - 1]
所以此时递推公式为:
d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] + 1 dp[i][j] = dp[i-1][j-1]+1 dp[i][j]=dp[i−1][j−1]+1
2、text1[i - 1] != text2[j - 1]
例子:s:abc t:abcde
本题是判断s是否为t的子串,所以t的长度必然大于等于s,所以只能在t子串上做删减操作
所以此时递推公式是:
d p [ i ] [ j ] = d p [ i ] [ j − 1 ] dp[i][j] = dp[i][j-1] dp[i][j]=dp[i][j−1] -
初始化
dp[i][0]和dp[0][j]显然都是没有意义的,即二维数组的第一行和第一列,将其全部初始化为0即可。其余数值因为会在递推公式中被覆盖,所以也都初始化为0,这样可以使得代码相对简洁。 -
遍历顺序
显然遍历是从上到下,从左到右
代码:
class Solution {
public:
bool isSubsequence(string s, string t) {
vector<vector<int>>dp(s.size() + 1, vector<int>(t.size() + 1, 0));
for(int i = 1; i <= s.size(); i++)
{
for(int j = 1; j <= t.size(); 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[s.size()][t.size()] == s.size() ? true : false;
}
};
总结
类似最大公共子序和,区别在于本题只需要在t字符串上做删除操作
LeetCode 115 不同的子序列
题目链接:https://leetcode.cn/problems/distinct-subsequences/
思路:
-
dp数组的含义
dp[i][j]代表以i-1结尾的s子串出现以j-1结尾的t子串的个数 -
递推公式
本题有两种情况:
s[i - 1] == t[j - 1]
此时有两种选择:
1、选择将s字符串中i-1位置的字符和t字符串中j-1位置的字符匹配,那么此时
d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] dp[i][j] = dp[i-1][j-1] dp[i][j]=dp[i−1][j−1]因为s上第i-1的位置已经匹配上t上的j-1的位置,那么此时就要查看s中以i-2结尾的子串出现以j-2结尾的子串的个数。
2、不选择将字符串s中i-1位置的字符和t字符串中j-1位置的字符匹配,即此时要考虑以i-2结尾的s子串出现以j-1结尾的t子串的个数。
例子:s:bagg t:bag
当 i = 4 i=4 i=4, j = 3 j=3 j=3,此时 s [ i − 1 ] = g s[i-1]=g s[i−1]=g, t [ j − 1 ] = g t[j-1]=g t[j−1]=g,不选择匹配的话即在bag(s[0:i-2])中找有包含bag(t[0:i-1])子串有多少个
所以此时递推公式为:
d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j] = dp[i-1][j] dp[i][j]=dp[i−1][j]
所以整体递推公式为:
d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] + d p [ i − 1 ] [ j ] dp[i][j] =dp[i-1][j-1]+dp[i-1][j] dp[i][j]=dp[i−1][j−1]+dp[i−1][j]
s[i - 1] != t[j - 1]
本题是判断s包含多少个t,所以s的长度必然大于等于t,所以只能在s子串上做删减操作
所以此时递推公式是:
d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j] = dp[i-1][j] dp[i][j]=dp[i−1][j] -
初始化
d p [ i ] [ 0 ] dp[i][0] dp[i][0]代表s为正常子串,t为空字串的情况,显然, d p [ i ] [ 0 ] = 1 dp[i][0]=1 dp[i][0]=1
d p [ 0 ] [ j ] dp[0][j] dp[0][j]代表s为空字串,在空字串上要包含有正常子串,显然不可能。所以 d p [ 0 ] [ j ] = 0 dp[0][j]=0 dp[0][j]=0 -
遍历顺序
显然遍历是从上到下,从左到右
代码:
class Solution {
public:
int numDistinct(string s, string t) {
vector<vector<uint64_t>>dp(s.size() + 1, vector<uint64_t>(t.size() + 1, 0));
for(int i = 0; i <= s.size(); i ++)
{
dp[i][0] = 1;
}
for(int i = 1; i <= s.size(); i++)
{
for(int j = 1; j <= t.size(); j++)
{
if(s[i - 1] == t[j - 1])
{
dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
}
else
dp[i][j] = dp[i - 1][j];
}
}
return dp[s.size()][t.size()];
}
};
总结
重点要理解 当 s [ i − 1 ] = = t [ j − 1 ] 当s[i-1]==t[j-1] 当s[i−1]==t[j−1]的时候要有两种情况,要把两种情况都考虑进去。
今日总结:
开始学习编辑距离的问题。