题目链接
英文链接:https://leetcode.com/problems/distinct-subsequences/
中文链接:https://leetcode-cn.com/problems/distinct-subsequences/
题目详述
给定一个字符串 S 和一个字符串 T,计算在 S 的子序列中 T 出现的个数。
一个字符串的一个子序列是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串。(例如,”ACE” 是 “ABCDE” 的一个子序列,而 “AEC” 不是)
示例 1:
1 | 输入: S = "rabbbit", T = "rabbit" |
示例 2:
1 | 输入: S = "babgbag", T = "bag" |
题目详解
可以换一种思考的方式:用 S 中的字符,按顺序匹配 T 中的字符,问有多少种方式可以匹配完 T 中的所有字符。可以运用动态规划解答。
f[i][j]
表示用 S 的前 i 个字符,能匹配完 T 的前 j 个字符的方案数。- 初始化
f[i][0] = 1, 0 <= i <= len(S)
,这是因为 T 为空,从任意一个字符开始匹配即可。 - 状态转移方程:
- 如果
S[i - 1] != T[j - 1]
,则S[i - 1]
不能匹配T[j - 1]
,所以f[i][j] = f[i - 1][j]
。 - 如果
S[i - 1] == T[j - 1]
,则S[i - 1]
可以选择匹配T[j - 1]
,也可以选择不匹配,所以f[i][j] = f[i - 1][j] + f[i - 1][j - 1]
。
- 如果
- 假设 S 的长度是 m,T 的长度是 n,则共有 m*n 个状态,状态转移的复杂度是
O(1)
,所以时间复杂度是O(mn)
。
1 | public class LeetCode_00115 { |
对 i 而言,由于当前状态只与上一层状态有关,可以对状态进行压缩,将空间复杂度从二维降为一维。dp[i][j]
会用到 dp[i - 1][j]
和 dp[i - 1][j - 1]
,为了避免覆盖 dp[i - 1][j - 1]
,j 的循环应该逆序。
1 | public class LeetCode_00115 { |