publicclassSolution { publicintDistinctSubseqII(string s) { constint MOD = 1000000007; int[] last = newint[26]; Array.Fill(last, -1);
int n = s.Length; int[] f = newint[n]; Array.Fill(f, 1); for (int i = 0; i < n; ++i) { for (int j = 0; j < 26; ++j) { if (last[j] != -1) { f[i] = (f[i] + f[last[j]]) % MOD; } } last[s[i] - 'a'] = i; }
int ans = 0; for (int i = 0; i < 26; ++i) { if (last[i] != -1) { ans = (ans + f[last[i]]) % MOD; } } return ans; } }
[sol1-Python3]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
classSolution: defdistinctSubseqII(self, s: str) -> int: mod = 10**9 + 7 last = [-1] * 26
n = len(s) f = [1] * n for i, ch inenumerate(s): for j inrange(26): if last[j] != -1: f[i] = (f[i] + f[last[j]]) % mod last[ord(s[i]) - ord("a")] = i ans = 0 for i inrange(26): if last[i] != -1: ans = (ans + f[last[i]]) % mod return ans
funcdistinctSubseqII(s string) (ans int) { const mod int = 1e9 + 7 last := make([]int, 26) for i := range last { last[i] = -1 } n := len(s) f := make([]int, n) for i := range f { f[i] = 1 } for i, c := range s { for _, j := range last { if j != -1 { f[i] = (f[i] + f[j]) % mod } } last[c-'a'] = i } for _, i := range last { if i != -1 { ans = (ans + f[i]) % mod } } return }
复杂度分析
时间复杂度:O(n|\Sigma|),其中 n 是字符串 s 的长度,\Sigma 是字符集,在本题中 |\Sigma|=26。即为动态规划需要的时间。
classSolution { public: intdistinctSubseqII(string s){ vector<int> g(26, 0); int n = s.size(); for (int i = 0; i < n; ++i) { int total = 1; for (int j = 0; j < 26; ++j) { total = (total + g[j]) % mod; } g[s[i] - 'a'] = total; } int ans = 0; for (int i = 0; i < 26; ++i) { ans = (ans + g[i]) % mod; } return ans; }
publicclassSolution { publicintDistinctSubseqII(string s) { constint MOD = 1000000007; int[] g = newint[26]; int n = s.Length; for (int i = 0; i < n; ++i) { int total = 1; for (int j = 0; j < 26; ++j) { total = (total + g[j]) % MOD; } g[s[i] - 'a'] = total; }
int ans = 0; for (int i = 0; i < 26; ++i) { ans = (ans + g[i]) % MOD; } return ans; } }
intdistinctSubseqII(char * s) { int n = strlen(s); int g[26]; memset(g, 0, sizeof(g)); for (int i = 0; i < n; ++i) { int total = 1; for (int j = 0; j < 26; ++j) { total = (total + g[j]) % mod; } g[s[i] - 'a'] = total; } int ans = 0; for (int i = 0; i < 26; ++i) { ans = (ans + g[i]) % mod; } return ans; }
[sol2-JavaScript]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
var distinctSubseqII = function(s) { constMOD = 1000000007; const g = newArray(26).fill(0); const n = s.length; for (let i = 0; i < n; ++i) { let total = 1; for (let j = 0; j < 26; ++j) { total = (total + g[j]) % MOD; } g[s[i].charCodeAt() - 'a'.charCodeAt()] = total; }
let ans = 0; for (let i = 0; i < 26; ++i) { ans = (ans + g[i]) % MOD; } return ans; };
[sol2-Golang]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
funcdistinctSubseqII(s string) (ans int) { const mod int = 1e9 + 7 g := make([]int, 26) for _, c := range s { total := 1 for _, v := range g { total = (total + v) % mod } g[c-'a'] = total } for _, v := range g { ans = (ans + v) % mod } return }
复杂度分析
时间复杂度:O(n|\Sigma|),其中 n 是字符串 s 的长度,\Sigma 是字符集,在本题中 |\Sigma|=26。即为动态规划需要的时间。
空间复杂度:O(|\Sigma|)。即为数组 g 和 last 需要的空间。
方法三:继续优化的动态规划
思路与算法
观察方法二中的状态转移方程:
g[o_i] = 1 + \sum_{0 \leq k < 26} g[k]
由于我们的答案是数组 g 的和,而遍历 s[i] 后只有 g[o_i] 的值发生了变化。因此我们可以使用一个变量 total 直接维护数组 g 的和,每次将 g[o_i] 的值更新为 1 + \textit{total,再将 total 的值增加 g[o_i] 的变化量即可。
代码
[sol3-C++]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
classSolution { public: intdistinctSubseqII(string s){ vector<int> g(26, 0); int n = s.size(), total = 0; for (int i = 0; i < n; ++i) { int oi = s[i] - 'a'; int prev = g[oi]; g[oi] = (total + 1) % mod; total = ((total + g[oi] - prev) % mod + mod) % mod; } return total; }
private: staticconstexprint mod = 1000000007; };
[sol3-Java]
1 2 3 4 5 6 7 8 9 10 11 12 13 14
classSolution { publicintdistinctSubseqII(String s) { finalintMOD=1000000007; int[] g = newint[26]; intn= s.length(), total = 0; for (inti=0; i < n; ++i) { intoi= s.charAt(i) - 'a'; intprev= g[oi]; g[oi] = (total + 1) % MOD; total = ((total + g[oi] - prev) % MOD + MOD) % MOD; } return total; } }
[sol3-C#]
1 2 3 4 5 6 7 8 9 10 11 12 13 14
publicclassSolution { publicintDistinctSubseqII(string s) { constint MOD = 1000000007; int[] g = newint[26]; int n = s.Length, total = 0; for (int i = 0; i < n; ++i) { int oi = s[i] - 'a'; int prev = g[oi]; g[oi] = (total + 1) % MOD; total = ((total + g[oi] - prev) % MOD + MOD) % MOD; } return total; } }
g = [0] * 26 total = 0 for i, ch inenumerate(s): oi = ord(s[i]) - ord("a") g[oi], total = (total + 1) % mod, (total * 2 + 1 - g[oi]) % mod return total
[sol3-C]
1 2 3 4 5 6 7 8 9 10 11 12 13 14
constint mod = 1e9 + 7;
intdistinctSubseqII(char * s) { int g[26]; memset(g, 0, sizeof(g)); int n = strlen(s), total = 0; for (int i = 0; i < n; ++i) { int oi = s[i] - 'a'; int prev = g[oi]; g[oi] = (total + 1) % mod; total = ((total + g[oi] - prev) % mod + mod) % mod; } return total; }
[sol3-JavaScript]
1 2 3 4 5 6 7 8 9 10 11 12
var distinctSubseqII = function(s) { constMOD = 1000000007; const g = newArray(26).fill(0); let n = s.length, total = 0; for (let i = 0; i < n; ++i) { let oi = s[i].charCodeAt() - 'a'.charCodeAt(); let prev = g[oi]; g[oi] = (total + 1) % MOD; total = ((total + g[oi] - prev) % MOD + MOD) % MOD; } return total; };
[sol3-Golang]
1 2 3 4 5 6 7 8 9 10 11
funcdistinctSubseqII(s string) (total int) { const mod int = 1e9 + 7 g := make([]int, 26) for _, c := range s { oi := c - 'a' prev := g[oi] g[oi] = (total + 1) % mod total = ((total+g[oi]-prev)%mod + mod) % mod } return }
复杂度分析
时间复杂度:O(n + |\Sigma|)。其中 n 是字符串 s 的长度,\Sigma 是字符集,在本题中 |\Sigma|=26。初始化需要的时间为 O(|\Sigma|),动态规划需要的时间的为 O(n)。