https://leetcode.com/problems/distinct-subsequences/
你會得到字串s
和t
,請從字串s
中的所有字母,找出有幾種組合能組成字串t
一開始的想法是用回朔法把所有可行的組合找出來,但是時間超過系統要求(Time Limit Exceeded),想法如下
先列出字串s
中所有組成t
所需的字母位置,以example2為例:{b:[0,2,4]}
、{a:[1,5]}
、{g:[3,6]}
接著,從b挑出一個位置i
、a挑出一個大於i
的位置j
、g挑出一個大於j
的位置k
重複幾次找出i, j, k
的動作並組合: [0, 1, 3]、[0, 1, 5]、[0, 5, 6]、[2, 5, 6]、[4, 5, 6]
class Solution:
def numDistinct(self, s: str, t: str) -> int:
s_dict = defaultdict(list)
for i in range(len(s)):
s_dict[s[i]].append(i)
def backtracking(level, previ, memo):
if (level, previ) in memo:
return memo[(level, previ)]
if level == len(t):
return 1
ans = 0
for i in s_dict[t[level]]:
if previ < i:
ans += backtracking(level+1, i, memo)
memo[(level, previ)] = ans
return ans
return backtracking(0, -1, {})
第二個解法則是看別人答案來的,先看看程式碼吧
class Solution:
def numDistinct(self, s: str, t: str) -> int:
@cache
def dp(i, j):
if j == len(t):
return 1
if i == len(s):
return 0
if len(s) - i < len(t) - j:
return 0
if s[i] == t[j]:
return dp(i+1, j+1) + dp(i+1, j)
return dp(i+1, j)
return dp(0, 0)
這個方法則是從兩個字串的第一個字母開始比對,我們先看看下面這部分,並同樣以example2當例子
if s[i] == t[j]:
return dp(i+1, j+1) + dp(i+1, j)
return dp(i+1, j)
return dp(i+1, j+1) + dp(i+1, j)
我們分別來看這兩個遞迴的意思
b
),我們就找下組成字串t
需要的字母(找a
)b
)下面這段也很重要,可以節省很多時間,意思是s
剩下的長度比t
剩下的程度還短的話,就不可能組出t
了
if len(s) - i < len(t) - j:
return 0
最後,@cache
要記得加上去,他是叫你的cache採用LRU策略,沒加的話過不了
大家中秋快樂