Leetcode 940:不同的子序列 II(最詳細的解法!!!)
阿新 • • 發佈:2018-11-16
給定一個字串 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
如有問題,希望大家指出!!!