Leetcode 115:不同的子序列(最詳細的解法!!!)
阿新 • • 發佈:2018-11-16
給定一個字串 S 和一個字串 T,計算在 S 的子序列中 T 出現的個數。
一個字串的一個子序列是指,通過刪除一些(也可以不刪除)字元且不干擾剩餘字元相對位置所組成的新字串。(例如,"ACE"
是 "ABCDE"
的一個子序列,而 "AEC"
不是)
示例 1:
輸入: S = "rabbbit", T = "rabbit"
輸出: 3
解釋:
如下圖所示, 有 3 種可以從 S 中得到 "rabbit" 的方案。
(上箭頭符號 ^ 表示選取的字母)
rabbbit
^^^^ ^^
rabbbit
^^ ^^^^
rabbbit
^^^ ^^^
示例 2:
輸入: S = "babgbag", T = "bag" 輸出: 5 解釋: 如下圖所示, 有 5 種可以從 S 中得到 "bag" 的方案。 (上箭頭符號 ^ 表示選取的字母) babgbag ^^ ^ babgbag ^^ ^ babgbag ^ ^^ babgbag ^ ^^ babgbag ^^^
解題思路
我們先進行一些準備工作。
s_len, t_len, result = len(s), len(t), 0
if s_len < t_len:
return result
if s_len == t_len:
if s == t:
return 1
return result
首先你一定可以想到這樣的暴力解法。從S
中選出len(T)
大小的全部組合,然後判斷這些組合中有多少個和T
是一樣的。
for i in combinations(s, t_len):
new_t = "".join(i)
if new_t == t:
result += 1
這種匹配問題,我們很容易想到通過動態規劃來做。但是如果我們直接思考遞迴過程,很難想出具體的遞推公式。對於兩個字串的比較,在我們沒有其他辦法的時候,我們不妨先建立一個二維的陣列,觀察一下兩個字串的匹配情況
Ø r a b b b i t
Ø 1 1 1 1 1 1 1 1
r 0 1 1 1 1 1 1 1
a 0 0 1 1 1 1 1 1
b 0 0 0 1 2 3 3 3
b 0 0 0 0 1 3 3 3
i 0 0 0 0 0 0 3 3
t 0 0 0 0 0 0 0 3
首先說明一下上面這個矩陣的含義,橫向表示S
,縱向表示T
,每個元素表示當前橫座標向左的S
字串最多可以匹配幾次當前縱座標向上的T
3,4
,此時S=rabb
,而T=rab
,所以可以匹配兩次。觀察上面這個矩陣,我們可以的到這樣的規律,假設我們此時的座標是(i,j)
,如果S[j]==T[i]
,我們的矩陣mem[i+1][j+1]=mem[i][j]+mem[i+1][j]
,否則的話mem[i+1][j+1]=mem[i+1][j]
。
class Solution:
def numDistinct(self, s, t):
"""
:type s: str
:type t: str
:rtype: int
"""
s_len, t_len = len(s), len(t)
mem = [[0]*(s_len+1) for _ in range(t_len+1)]
for i in range(s_len+1):
mem[0][i] = 1
for i in range(t_len):
for j in range(s_len):
if s[j] == t[i]:
mem[i+1][j+1] = mem[i][j] + mem[i+1][j]
else:
mem[i+1][j+1] = mem[i+1][j]
return mem[-1][-1]
如果我們從另外一個角度去看這個問題,我們按照遞迴的思路去考慮,每次遍歷s
的一個元素,然後思考t
的字首在s[:i]
中出現的次數,我們會得到這樣的矩陣
r a b b i t
0 0 0 0 0 0 Ø
1 0 0 0 0 0 r
1 1 0 0 0 0 a
1 1 1 0 0 0 b
1 1 2 1 0 0 b
1 1 3 3 0 0 b
1 1 3 3 3 0 i
1 1 3 3 3 3 t
我們不難發現這樣的規律,我們每次計算新的一行當中的元素,假設此時的座標是i,j
,如果s[i]==t[j]
,我們此時的第j+1
列的值,會等於原來j+1
列的值再加上原來j
列的值,也就是↘和↓相加。
class Solution:
def numDistinct(self, s, t):
"""
:type s: str
:type t: str
:rtype: int
"""
t_len = len(t)
mem = [1]+[0]*t_len
for s_c in s:
for i in range(t_len-1, -1, -1):
if t[i] == s_c:
mem[i+1] += mem[i]
return mem[-1]
是不是很酷!!!
我將該問題的其他語言版本新增到了我的GitHub Leetcode
如有問題,希望大家指出!!!