1 392. 判断子序列
方法1:双指针
class Solution {
public:
bool isSubsequence(string s, string t) {
// 双指针
int l = 0;
for(int i = 0; i < t.size(); i++)
if(t[i] == s[l])l++;
if(l == s.size())return 1;
else return 0;
}
};
方法2:dp。和1143. 最长公共子序列 差不多。AC代码:
class Solution {
public:
// dp
int dp[105][10010]; // dp[i][j] 表示s的前0..i-1的字符串 和 t的前0..j-1的字符串最长公共子序列长度
/*
if(s[i-1] == t[j-1])
dp[i][j] = dp[i-1][j-1] + 1;
else dp[i][j] = max(dp[i-1][j],dp[i][j-1]);
初始化默认都是0
i++j++
模拟——
*/
bool isSubsequence(string s, string t)
{
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] = max(dp[i-1][j],dp[i][j-1]);
}
}
if(dp[s.size()][t.size()] == s.size())return 1;
else return 0;
}
};
2 115. 不同的子序列
【难】本题的状态转移方程很难想到,看了题解学习到了!可以从“删除”的角度。具体看注释。
AC代码:
class Solution {
public:
unsigned long long dp[1010][1010]; // int只能达到31位有符号整数 long long 60+位 但是开long long爆内存 只能开ull
// dp[i][j] 表示s的前0..j-1个元素 是 t的前0..i-1个元素公共子序列的不同组合的个数 >> 错误!!!
// 由于s是连续的 所以含义定义的时候:
// 表示s的 0 .... j-1结尾的序列 存在t的以i-1结尾(不一定从0开始)的子序列 的个数
/*
看了题解 学习到了!!!!!!很妙~!!!!
if(t[i-1] == s[j-1])
{
dp[i][j] = dp[i-1][j-1] + dp[i][j-1];
// (t[i-1]就是和s[j-1]匹配:)t[0..i-2]由s[0..j-2]匹配得到 +
// (t[i-1]不是和s[j-1]匹配)t[0..i-1]由s[0..j-2]匹配得到
}
else
{
dp[i][j] = dp[i][j-1];
//(t[i-1]不是和s[j-1]匹配)t[0..i-1]由s[0..j-2]匹配得到
}
初始化:
dp[0][0] = 1;
dp[0][j] = 1; // i是0表示空串 即空串是s的0...j-1子串的个数为1
dp[i][0] = 0; // t的0...i-1子串是空串的子序列的个数为0
i++ j++
模拟——
*/
int numDistinct(string s, string t)
{
dp[0][0] = 1;
for(int j = 1; j <= s.size();j++)dp[0][j] = 1;
for(int i = 1; i <= t.size(); i++)
{
for(int j = 1; j <= s.size();j++)
{
if(t[i-1] == s[j-1])
{
dp[i][j] = dp[i-1][j-1] + dp[i][j-1];
// (t[i-1]就是和s[j-1]匹配:)t[0..i-2]由s[0..j-2]匹配得到 +
// (t[i-1]不是和s[j-1]匹配)t[0..i-1]由s[0..j-2]匹配得到
}
else
{
dp[i][j] = dp[i][j-1];
//(t[i-1]不是和s[j-1]匹配)t[0..i-1]由s[0..j-2]匹配得到
}
}
}
return dp[t.size()][s.size()] > INT_MAX ? -1:dp[t.size()][s.size()] ; //第65个测试样例有个坑点
}
};