392. 判断子序列
1.代码
class Solution {
public:
bool isSubsequence(string s, string t) {
vector<vector<int>>f(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]) f[i][j] = f[i - 1][j - 1] + 1;
else f[i][j] = max(f[i][j - 1], f[i - 1][j]);
}
}
if(f[s.size()][t.size()] == s.size()) return true;
else return false;
}
};
2.递归五部曲
题意:
1.确定dp数组和下标的含义
题目是求子序列,其实就和前面的最长公共子序列差不多,dp[i][j]就是下标再0到i - 1和下标0 到j - 1的两个数组最长公共子序列
2.确定递推公式
由状态递推可知,dp[i][j]可由两种情况
一.当i - 1和j - 1代表的元素相同时,dp[i][j]只能由上一个状态dp[i - 1][j - 1]得来,是i - 1和j - 1代表的数组之间的最长公共子序列,加上一就是结果
二.当不相等时,上一个状态是dp[i - 1][j]和dp[i][j - 1]这两个状态推导出来的,最大值就是结果,代表当前可以推测出来的最长公共子序列
三.初始化dp数组
当下标有一个为0时,最长公共子序列就是,所以不必初始化
四.确定递推顺序
循环遍历两个数组遍历全部范围,知道求出最长范围的公共子序列当等于目标序列就是第一个字符串的长度就时正确答案
五.模拟
115. 不同的子序列
1.代码
class Solution {
public:
int numDistinct(string s, string t) {
vector<vector<uint64_t>>f(s.size() + 1, vector<uint64_t>(t.size() + 1, 0));
for (int i = 0; i <= s.size(); i++) f[i][0] = 1;
for (int j = 1; j <= t.size(); j++) f[0][j] = 0;
for (int i = 1; i <= s.size(); i++) {
for (int j = 1; j <= t.size(); j++) {
if (s[i - 1] == t[j - 1]) f[i][j] = f[i - 1][j - 1] + f[i - 1][j];
else f[i][j] = f[i - 1][j];
}
}
return f[s.size()][t.size()];
}
};
2.递归五部曲
题意:删除第一个字符串的一些字符能够得到第二个字符有多少方式
1.确定dp数组和其下标含义
观察结果可以怎么推导出来根据题意,dp[i][j]代表在第一个字符串0到i - 1下标中选择删除一部分字符,能够得到第二个字符串0 - j-1下标之间字符有多少个,最后就能推导出结果
2.确定递推公式
当i - 1和j - 1两个字符相同是,得到当前目标字符串的个数是dp[i - 1][j - 1]+dp[i - 1][j],两个方向的相加
当不想同时,dp[i][j] = dp[i - 1][j],代表从第一个元素下标到i - 1能有多少种方式到目标字符串
if (s[i - 1] == t[j - 1]) f[i][j] = f[i - 1][j - 1] + f[i - 1][j];
else f[i][j] = f[i - 1][j];
3.初始化
由推导方向可知只能从两个方向推导,dp[i][0]为空字符串的方法多少种,由题意可知为1种,删除全部元素
dp[0][j]为0种,从空字符串中选不可能得到j-1字符串
4.确定递推顺序
也是遍历两个数组不端推导出,第一个字符串中删除元素能得到第二个字符串的方法个数
5.模拟