📅  最后修改于: 2023-12-03 14:58:25.274000             🧑  作者: Mango
给定两个字符串 S 和 T,求 S 的子序列中有多少个 T。
例如, S = "rabbbit",T = "rabbit",S 的子序列中有 3 个 T。
本题是一道经典的动态规划问题。设 $dp[i][j]$ 表示在字符串 $S[0:i]$ 中,$T[0:j]$ 出现的子序列的个数。
边界条件为 $dp[i][0] = 1$。即,无论 $S$ 如何,当 $T$ 是空字符串时,$dp[i][0]$ 均为 1。而 $dp[0][j]$ 均为 0,因为若 $S$ 是空字符串,其不可能有 $T$ 的子序列。
状态转移方程为:
如果 $S[i-1] \neq T[j-1]$,则 $dp[i][j] = dp[i-1][j]$。即,若 $S$ 的第 $i$ 个字符不等于 $T$ 的第 $j$ 个字符,则 $S[0:i]$ 中有 $T[0:j]$ 出现的子序列个数与 $S[0:i-1]$ 中有 $T[0:j]$ 出现的子序列个数相同。
如果 $S[i-1] = T[j-1]$, 则 $dp[i][j] = dp[i-1][j] + dp[i-1][j-1]$,意为 $S[0:i]$ 中既可以不包括第 $i$ 个字符(于是有 $dp[i-1][j]$ 种情况),也可以包括第 $i$ 个字符(此时,$S[0:i-1]$ 中有 $T[0:j-1]$ 出现的子序列 $dp[i-1][j-1]$ 种情况,对它们分别加上第 $i$ 个字符即可得到 $S[0:i]$ 中包括第 $i$ 个字符的情况)。
最终可以返回 $dp[n][m]$,其中 $n$ 是 $S$ 的长度,$m$ 是 $T$ 的长度。
以下是完整的示例代码:
def num_distinct(s: str, t: str) -> int:
n, m = len(s), len(t)
dp = [[0] * (m+1) for _ in range(n+1)]
for i in range(n+1):
dp[i][0] = 1
for i in range(1, n+1):
for j in range(1, m+1):
if s[i-1] != t[j-1]:
dp[i][j] = dp[i-1][j]
else:
dp[i][j] = dp[i-1][j] + dp[i-1][j-1]
return dp[n][m]
本算法的时间复杂度为 $O(nm)$,其中 $n$ 是 $S$ 的长度, $m$ 是 $T$ 的长度。
空间复杂度为 $O(nm)$,主要是存储状态数组 $dp$。