Skip to main content

115.不同的子序列

标签: dynamic-programming, string

难度: Hard

通过率: 48.92%

原题链接: https://leetcode.com/problems/distinct-subsequences/description/

题目描述

给定两个字符串 sstt,返回 ss 的不同子序列中等于 tt 的个数。

解题思路

这个问题可以通过动态规划来解决。我们定义一个二维数组 dpdp,其中 dp[i][j]dp[i][j] 表示 s[0:i]s[0:i] 中子序列等于 t[0:j]t[0:j] 的个数。显然,如果 j=0j = 0,即 tt 是空串,那么 s[0:i]s[0:i] 总有一个子序列等于空串,这个子序列就是空串本身,所以 dp[i][0]=1dp[i][0] = 1 对于所有 ii 生效。如果 $i = 0$ (但 $j \neq 0$),那么 $dp[0][j] = 0$,因为没有任何子序列。接下来,我们讨论如何填充 dpdp 数组的其他部分:

  • 如果当前字符 s[i]s[i] 等于 t[j]t[j],那么我们有两种选择:一是选择使用 s[i]s[i],这种情况下 dp[i][j]=dp[i1][j1]dp[i][j] = dp[i-1][j-1];二是不使用 s[i]s[i],这种情况下 dp[i][j]=dp[i1][j]dp[i][j] = dp[i-1][j]。总体而言,我们有 dp[i][j]=dp[i1][j]+dp[i1][j1]dp[i][j] = dp[i-1][j] + dp[i-1][j-1]
  • 如果当前字符 s[i]s[i] 不等于 t[j]t[j],那么我们只能选择不使用 s[i]s[i],此时 dp[i][j]=dp[i1][j]dp[i][j] = dp[i-1][j]

最终答案是 dp[len(s)][len(t)]dp[len(s)][len(t)]

代码实现

def numDistinct(s: str, t: str) -> int:    # 初始化 dp 数组,进行填充    m, n = len(s), len(t)    dp = [[0] * (n + 1) for _ in range(m + 1)]    # dp 初始化:空字符串匹配的情况    for i in range(m + 1):        dp[i][0] = 1    # 填充 dp 数组    for i in range(1, m + 1):        for j in range(1, n + 1):            # 若 s[i-1] == t[j-1],同时考虑使用和不使用这两个字符            if s[i - 1] == t[j - 1]:                dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1]            else:                # 仅考虑不使用 s[i-1]                dp[i][j] = dp[i - 1][j]    return dp[m][n]

复杂度分析

  • 时间复杂度: O(mn)O(m \cdot n),其中 mm 是字符串 ss 的长度,nn 是字符串 tt 的长度。`需要填充一个大小为 m×nm \times n 的 dp 表。
  • 空间复杂度: O(mn)O(m \cdot n),用于存储 dp 表。