📅  最后修改于: 2023-12-03 14:57:27.098000             🧑  作者: Mango
有时候我们需要计算一个字符串中不同的子序列的数量。子序列指的是从原字符串中删除若干个字符后得到的结果。
举个例子,字符串 abc
的子序列有 a
,b
,c
,ab
,ac
,bc
,abc
共 7 种。
下面介绍两种计算不同子序列数量的方法。
动态规划是一种求解优化问题的方法。对于计算不同子序列数量,可以采用动态规划的思想。
定义 dp[i][j]
表示字符串 s[:i]
(即前 i
个字符)和 t[:j]
(即前 j
个字符)的不同子序列数量。
考虑 s[i]
和 t[j]
是否匹配:
s[i] != t[j]
,此时 s[i]
和 t[j]
不能同时包含在任何一个子序列中,因此 dp[i][j]
只由 s[:i-1]
和 t[:j-1]
贡献。s[i] == t[j]
,则子序列可以包含 s[i]
(也可以不包含),此时 s[i-1]
和 t[j-1]
也可以在子序列中,此时 dp[i][j]
取决于 s[:i-1]
和 t[:j]
以及 s[:i]
和 t[:j-1]
。最终的不同子序列数量为 dp[m][n]
,其中 m
和 n
分别为字符串 s
和 t
的长度。
具体实现参考代码如下(Python3):
def numDistinct(s: str, t: str) -> int:
m, n = len(s), len(t)
dp = [[0] * (n + 1) for _ in range(m + 1)]
for i in range(m + 1):
dp[i][0] = 1
for i in range(1, m + 1):
for j in range(1, n + 1):
dp[i][j] = dp[i-1][j]
if s[i-1] == t[j-1]:
dp[i][j] += dp[i-1][j-1]
return dp[m][n]
递归计算不同子序列数量的思路如下:
s
去掉最后一个字符和 t
的不同子序列数量。具体实现参考代码如下(Python3):
def numDistinct(s: str, t: str) -> int:
if not t:
return 1
if not s:
return 0
if s[-1] == t[-1]:
return numDistinct(s[:-1], t[:-1]) + numDistinct(s[:-1], t)
else:
return numDistinct(s[:-1], t)
以上两种方法的时间复杂度均为 $O(mn)$,其中 $m$ 和 $n$ 分别为字符串 s
和 t
的长度。递归方法的空间复杂度为 $O(mn)$,动态规划方法的空间复杂度为 $O(mn)$ 或 $O(n)$。