倒计时day6。第一题是判断子序列https://leetcode.cn/problems/is-subsequence/description/,动规五步曲分析如下:dp[i][j]表示以下标为i - 1的字符串1与下标为j - 1的字符串2的相同子序列长度。当发现str1[i - 1] == str2[j - 1]时,相同子序列长度加一,dp[i][j]=dp[i - 1][j - 1] + 1,当发现str1[i - 1] != str2[j - 1]时,说明此次遍历位置字符并不相同,则dp[i][j]的状态不发生改变,即dp[i][j] = dp[i][j - 1]。dp[i][0],dp[0][j]表示字符串与空串的匹配情况,故dp[i][0],dp[0][j]均初始化为0。从前向后遍历dp数组。一通分析下来,不难发现思路与最长公共子序列https://leetcode.cn/problems/longest-common-subsequence/description/很相似,事实上,当两个字符串的最长公共子序列为其中一个字符串时,即可判断s是t的一个子序列。
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];}}if (dp[s.size()][t.size()] == s.size()) return true;return false;}
};
第二题是不同子序列https://leetcode.cn/problems/distinct-subsequences/description/,上一题目的进阶版本。dp[i][j]表示以i - 1为结尾的字符串s中出现以j - 1为结尾的字符串t的个数。若s[i - 1]==t[j - 1],说明可能会出现一次新的匹配,只需观察i-1,j-1之前的匹配情况,判断能否出现一次新的匹配,同时不能丢掉以前的匹配数量,从i-1之前的匹配数量为dp[i-1][j]。综上dp[i][j] = dp[i-1][j-1] + dp[i - 1][j]。若s[i - 1] != t[j - 1],说明此次并未出现新的匹配,dp[i][j]的状态与遍历i-1前相同,即dp[i][j] = dp[i - 1][j]。当j=0时,t为空字符串,s只有当i=0时才会发生一次匹配,故dp[i][0] = 1;而i=0时,空字符串中不会含有字符串t,故dp[0][j] = 0。i,j同时为0时,空字符串中紧=仅含有一个空字符串,dp[0][0] = 1。从小到大遍历dp数组。
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()];}
};