940. 不同的子序列 II
题目描述
给定一个字符串 s,计算 s 的 不同非空子序列 的个数。因为结果可能很大,所以返回答案需要对 10^9 + 7 取余 。
字符串的 子序列 是经由原字符串删除一些(也可能不删除)字符但不改变剩余字符相对位置的一个新字符串。
- 例如,
"ace"是"abcde"的一个子序列,但"aec"不是。
示例 1:
输入:s = "abc" 输出:7 解释:7 个不同的子序列分别是 "a", "b", "c", "ab", "ac", "bc", 以及 "abc"。
示例 2:
输入:s = "aba" 输出:6 解释:6 个不同的子序列分别是 "a", "b", "ab", "ba", "aa" 以及 "aba"。
示例 3:
输入:s = "aaa" 输出:3 解释:3 个不同的子序列分别是 "a", "aa" 以及 "aaa"。
提示:
1 <= s.length <= 2000s仅由小写英文字母组成
解法
方法一:动态规划
思考
不同非空子序列的个数,\(n\le 2000\),不能枚举子集。以末字符分类:\(f[c]\) 表示当前以 \(c\) 结尾的不同子序列数。读入 \(c\) 时,它可以接在此前任意子序列之后,也可以单独成串,故 \(f[c]\leftarrow \sum f+1\),重复字符会覆盖旧的以 \(c\) 结尾的集合。
我们定义 \(f[i]\) 表示以第 \(i\) 个小写字母结尾的不同子序列的个数。初始时 \(f\) 中所有元素均为 \(0\)。
遍历字符串 \(s\),对于当前字符 \(c\),我们将 \(f[c]\) 更新为 \(\sum_{i=0}^{25} f[i] + 1\)。其中 \(\sum_{i=0}^{25} f[i]\) 表示此前已经得到的所有不同子序列的个数,而 \(+1\) 表示字符 \(c\) 本身也可以作为一个子序列。
最后,答案为 \(\sum_{i=0}^{25} f[i]\),对 \(10^9 + 7\) 取余。
时间复杂度 \(O(n \times C)\),空间复杂度 \(O(C)\)。其中 \(n\) 是字符串 \(s\) 的长度,而 \(C\) 是字符集的大小,本题中 \(C = 26\)。
1 2 3 4 5 6 7 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
1 2 3 4 5 6 7 8 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
方法二:动态规划优化
思考
方法一每次更新要扫 \(26\) 个格子。维护总和 \(\textit{ans}\),新增量为 \(\textit{ans}-f[i]+1\),即可 \(O(1)\) 更新 \(f[i]\) 与 \(\textit{ans}\)。
在方法一的基础上,我们可以维护一个变量 \(\textit{ans}\) 表示当前 \(f\) 数组中所有元素的和。每次更新 \(f[i]\) 时,新增的不同子序列个数为 \(\textit{ans} - f[i] + 1\),据此同时更新 \(\textit{ans}\) 与 \(f[i]\) 即可。
时间复杂度 \(O(n)\),空间复杂度 \(O(C)\)。
相似题目:
1 2 3 4 5 6 7 8 9 10 11 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
1 2 3 4 5 6 7 8 9 10 11 12 | |
1 2 3 4 5 6 7 8 9 10 11 12 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
1 2 3 4 5 6 7 8 9 10 11 12 | |