给定一个字符串 S
,计算 S
的不同非空子序列的个数。
因为结果可能很大,所以返回答案模 10^9 + 7.
示例 1:
输入:"abc"
输出:7
解释:7 个不同的子序列分别是 "a", "b", "c", "ab", "ac", "bc", 以及 "abc"。
示例 2:
输入:"aba"
输出:6
解释:6 个不同的子序列分别是 "a", "b", "ab", "ba", "aa" 以及 "aba"。
示例 3:
输入:"aaa"
输出:3
解释:3 个不同的子序列分别是 "a", "aa" 以及 "aaa"。
提示:
S
只包含小写字母。1 <= S.length <= 2000
解题思路
我们首先想到的思路是暴力破解,通过控制抽取S
中元素个个数,得到不同的组合,最后计算所有组合的总数。
from itertools import combinations
class Solution:
def distinctSubseqII(self, S):
"""
:type S: str
:rtype: int
"""
S, result = list(S), list()
count = 0
count += len(set(S))
if len(S) >= 2:
for i in range(2,len(S)+1):
result.append(set(combinations(S, i)))
for i in result:
for _ in i:
count += 1
return count%(10**9 + 7)
但是很明显这种做法不可取,太慢了。我们以这个思路为起点,如果我们想要计算S
的所有不同子序列个数,我们只需要知道除去最后一个元素的s[:-2]
所有不同子序列个数k
,那么我们最后的结果就是2k-以s[-1]结尾的所有子序列
。现在我们的问题就变成了,怎么计算以s[-1]结尾的所有子序列
?如果我们当前要考虑的元素,如S[-1]
,和之前的所有元素都不同,那么之前必然不会有以s[-1]结尾的所有子序列
。如果之前出现过当前考虑的元素的话,那么以s[-1]结尾的所有子序列
的个数就是最近一次以s[-1]结尾的所有子序列。例如
a a a
|
此时,我们知道我们之前的序列有a
、aa
和" "
。现在我们要将a
加上,也就是我们会有2*3=6
个子序列,但是之前序列中以a
结尾的序列有两个,所以我们的最后结果就是6-2=4
。但是因为我们最后不考虑" "
,所以还要减去1
。
class Solution:
def distinctSubseqII(self, S):
"""
:type S: str
:rtype: int
"""
pos, mod, cur_sum = [0]*26, 1e9+7, 1
for c in S:
old_sum = cur_sum
cur_sum = (cur_sum*2 - pos[ord(c) - 97]) % mod
pos[ord(c) - 97] = old_sum
return cur_sum - 1
还可以这样去思考,我们遍历输入的S
,例如
a b a
|
此时,我们碰到的以a
结尾的字符串只有a
。然后
a b a
|
此时,以b
结尾的字符串有ab
和b
,也就是a+b
," "+b
(上一次的结果加上b
)。(这其实就是trie
)
a b a
|
此时,以a
结尾的字符串有aba
、ba
、aa
和a
,也就是ab+a
,b+a
,a+a
," "+a
(上一次的结果加上a
)。所以我们最后的结果就是以a
和b
结尾的字符串个数总和。
实现上,我们需要建立一个26
大小的数组以容纳不同字母结尾的字符串个数。每当我们遍历到一个新的字母时,此时我们只要将数组中所有结果加起来然后再加1
即为以新的字母为结尾的字符串总数。最后我们只要将数组中的结果加起来即可。
class Solution:
def distinctSubseqII(self, S):
"""
:type S: str
:rtype: int
"""
end = [0] * 26
for c in S:
end[ord(c) - 97] = sum(end) + 1
return sum(end) % (10**9 + 7)
reference:
https://www.geeksforgeeks.org/count-distinct-subsequences/
我将该问题的其他语言版本添加到了我的GitHub Leetcode
如有问题,希望大家指出!!!