携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第10天,点击查看活动详情
题目
给定一个字符串 s 和一个字符串 t ,计算在 s 的子序列中 t 出现的个数。
字符串的一个 子序列 是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串。(例如,"ACE" 是 "ABCDE" 的一个子序列,而 "AEC" 不是)
题目数据保证答案符合 32 位带符号整数范围。
示例 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
提示
0 <= s.length, t.length <= 1000s和t由英文字母组成
题解
思路
整理s字符串。易知,子序列的开头和末尾字符和t串开头末尾字符一定相同,因此删掉s串开头和结尾的其他字符。
dp[i][j]: t串前i个字符在s串前j个字符中组成子序列的个数,0为NULL串
新读到的s串字符与t串末尾字符一致,可以更新子序列数目。新数目 = 两个末尾字符不连接的字串数目 + 两个末尾字符连接的字串数目。当我们删掉两个字符串末尾的字符,就是两个末尾字符不连接的字串数目,即dp[i-1][j-1]。当我们删掉 s 串的最后一个字符,t串的最后一个字符一定会与s串之前的另一个字符配对,就是两个末尾字符不连接的字串数目,即dp[i][j-1]
末尾字符不一致,上一个状态不会有更新
代码
class Solution:
def numDistinct(self, s: str, t: str) -> int:
if not t: return 1
while s and s[0] != t[0]: s = s[1:]
while s and s[-1] != t[-1]: s = s[:-1]
if len(s) < len(t): return 0
dp = [[0] * (len(s) + 1) for _ in range(len(t) + 1)]
for i in range(len(dp)):
for j in range(len(dp[0])):
if i == 0: # 空字符串是任何字符串的一个子序列
dp[i][j] = 1
elif i > j: # t串比s串长,一个子序列都没有
dp[i][j] = 0
else:
# 新读到的s串字符与t串末尾字符一致,可以更新子序列数目。
# 新数目 = 两个末尾字符不连接的字串数目 + 两个末尾字符连接的字串数目
if s[j-1] == t[i-1]:
dp[i][j] = dp[i][j-1] + dp[i-1][j-1]
# 末尾字符不一致,上一个状态不会有更新
else:
dp[i][j] = dp[i][j-1]
return dp[-1][-1]
结语
业精于勤,荒于嬉;行成于思,毁于随。