這道題是隨機選的,看了看題目,剛好和前段時間看了MIT6.00課程中的Dynamic Programming很像,於是就想着去解決試試。沒找到Dynamic Programming在這裏的切入點,運算結果是對的(報:Time Limit Exceeded),就是計算複雜度太高了——,當然十分慘烈。
940. Distinct Subsequences II
Given a string
S
, count the number of distinct, non-empty subsequences ofS
.Since the result may be large, return the answer modulo
10^9 + 7
.Example 1:
Input: "abc" Output: 7 Explanation: The 7 distinct subsequences are "a", "b", "c", "ab", "ac", "bc", and "abc".Example 2:
Input: "aba" Output: 6 Explanation: The 6 distinct subsequences are "a", "b", "ab", "ba", "aa" and "aba".Example 3:
Input: "aaa" Output: 3 Explanation: The 3 distinct subsequences are "a", "aa" and "aaa".
1. 直接求解
首先用的是課程中介紹的,結合遞歸方法和二叉樹,對所有結果進行遍歷(窮舉法,又一次用上了Brute Force)。往樹的左邊不選當前字符,往樹的右邊就選一個字符,一直遞歸下去就可以獲得所有的結果。結果集中包括空字符和重複的,因此選用Set進行過濾,得到不重複的結果,可以時間複雜度太高,在LeetCode中的時候計算超時了。
sub_set = set()
def get_sub_set(left_str, S):
if len(S) == 0:
print left_str
sub_set.add(left_str)
return
# print S
not_pick_one = left_str
get_sub_set(not_pick_one, S[1:])
# print 'notPick', pick_left
pick_one = left_str + S[0]
# print 'pick', pick_one
get_sub_set(pick_one, S[1:])
def distinctSubseqII(S):
"""
:type S: str
:rtype: int
"""
get_sub_set('', S)
return len(sub_set) - 1
def test():
s1 = 'abc'
print (7, distinctSubseqII(s1))
s1 = 'aba'
print (6, distinctSubseqII(s1))
s1 = 'aaa'
print (3, distinctSubseqII(s1))
test()
2. Dynamic Programming
昨天想了很久,沒想明白,睡覺的時候突然想起來,爲什麼結合前面二叉樹的分佈,來進行可視化操作呢?於是,在又經歷了近2小時,總於想透了,如下圖所示。
---
這裏有兩個假設
①在生成當前層字符時,所有來自上一層的字符都放在節點的左側。
②在生成當前層字符時,新生成的字符放在節點的右側。因此只需考慮新節點是否和之前的子字符重合即可。
我們需獲取字符‘aaa’的所有子字符串,按以下步驟
- index=0時,爲——空:
- index=1時,爲——,a
- index=2時,爲——,a,a,aa。但由於以前的經驗(當前字符都是在以前字符的基礎上生成),我們知道從index=0的中派生,會有結果,a。而index=1中,也有一個,並要進行向右派生。但此時不就和index=0中的情形重合了嗎?於是要刪去。最終結果爲:,a,aa
- index=3時,同理,可以過濾掉重複的結果a,aa,得到,a,aa,aaa
當我們要去求‘aaaa’的所有子字符串呢?以上步驟1-4不變,來看第五步,index=3的結果,直接繼承到樹的左側,現在只關注即將生成新結果的樹右側。本來index=3的結果產生來自於index=2,因此只需要去除此部分達到了去重的效果。
若在字符中混入了不同了字符,則判別方法類似,只需要找到同一個字符在上一個位置,並去除重複的數量即可——這裏包含的思想其實是分而治之。
解決方法如下,解決方法來自這個Discusss:
def distinctSubseqII(S):
"""
:type S: str
:rtype: int
"""
memo = {S[0]: 0}
dp = [0] + [0]*len(S)
dp[0] = 1
dp[1] = 2
mode_val = 10**9+7
for index in range(1, len(S)):
word = S[index]
# print index, 'word:', word
if word not in memo:
dp[index+1] = (2 * dp[index] % mode_val)
else:
# print memo[word]
value = 2 * dp[index] - dp[memo[word]]
dp[index+1] = value % mode_val
memo[word] = index
# print dp
return dp[-1] - 1
def test():
s1 = 'abc'
print (7, distinctSubseqII(s1))
s1 = 'aba'
print (6, distinctSubseqII(s1))
s1 = 'aaa'
print (3, distinctSubseqII(s1))
test()