【LeetCode-940】不同的子序列 II
问题
给定一个字符串 S,计算 S 的不同非空子序列的个数。
因为结果可能很大,所以返回答案模 10^9 + 7.
示例
输入: "aba"
输出: 6
解释: 6 个不同的子序列分别是 "a", "b", "ab", "ba", "aa" 以及 "aba"。
解答
class Solution {
public:
int distinctSubseqII(string S) {
int kMod = 1e9 + 7, n = S.size();
vector<int> memo(26, -1), dp(n + 1); // dp[0] = 0即空字符时不存在非空子序列
for (int i = 1; i <= n; i++) {
int cur = S[i - 1] - 'a';
if (memo[cur] < 0) dp[i] = (2 * dp[i - 1] + 1) % kMod;
else dp[i] = (2 * dp[i - 1] - dp[memo[cur]]) % kMod;
if (dp[i] < 0) dp[i] += kMod; // 因为减法和取模的原因,可能有负数
memo[cur] = i - 1;
}
return dp[n];
}
};
重点思路
字符串的动态规划。dp[i]
表示当前字符(S[i - 1]
)前所有可能的非空子序列,memo[i]
存储当前字符最后一次出现的角标。当前字符第一次出现时(即memo[cur] < 0
),增加的新不重复子序列为所有之前的子序列数量加上自己;当前字符不是第一次出现时,此时memo[cur]
表示该字符上一次出现的角标,此时新增的子序列数量为dp[i - 1] - dp[memo[cur]]
,因为之前已有重复的,所以新增子序列数量不再加上自己。