LeetCode_142_DistinctSubsequences


1. question: 不同的子序列(困难)

给定一个字符串 s 和一个字符串 t ,计算在 s 的子序列中 t 出现的个数。

字符串的一个 子序列 是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串。(例如,”ACE” 是 “ABCDE” 的一个子序列,而 “AEC” 不是)

题目数据保证答案符合 32 位带符号整数范围。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/distinct-subsequences

示例 1:

1
2
3
4
5
6
7
输入:s = "rabbbit", t = "rabbit"
输出:3
解释:
如下图所示, 有 3 种可以从 s 中得到 "rabbit" 的方案。
rabbbit
rabbbit
rabbbit

示例 2:

1
2
3
4
5
6
7
8
9
输入:s = "babgbag", t = "bag"
输出:5
解释:
如下图所示, 有 5 种可以从 s 中得到 "bag" 的方案。
babgbag
babgbag
babgbag
babgbag
babgbag

提示:

1
2
0 <= s.length, t.length <= 1000
s 和 t 由英文字母组成

2. answers

参考题解,这道题和判断子序列还是有区别的。判断子序列仅仅是判断是否是子序列,而本题除了判断是否是子序列之外,还要判断次数【这里的次数就是母串s可以找到多少个子序列,且子序列就是该子串t】。下面以一个小例子说明一下:

当判断“acbb”包含几个“acb”时,因为在遍历到各自的最后一个字符时,因为b=b,所以,acbb中最后一个b可以参加匹配,也可不参加匹配,【这里说的参加匹配,指的是是否匹配子串字符】,即出现了两种情况:

  1. 不参加匹配:“acb”包含几个“acb”,【因为不参加匹配,所以子串中完整无损】
  2. 参加匹配:“acb”包含几个“ac”,【因为参加匹配,所以子串中也要去掉匹配的字符】

显然“acbb”包含“acb”的子序列就是由上面两种情况总和组成,即1+1=2。同样上面的两种情况,也由该情况的子串组成。

当“acbb”中的b不等于“acb”中的b时,就类似上面的“acb”和“ac”比较,显然,因为“ac”是基准,所以只能是将b删掉,取决于“ac”包含了几个“ac”的情况。

本质上,因为要计算次数,所以同一个字符是否参与匹配就称为了关键。总体来看,和判断子序列类似,只不过定义的数组dp[i][j]不再表示子序列的长度,而是s[i]结尾的子串包含t[j]结尾的子串的子序列的个数。并且状态转移方程也不同。代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public class Solution_0142 {

public int numDistinct(String s, String t) {

if(t.length() == 0) return 1;
if(s.length() == 0) return 0;

// 定义数组
int[][] dp = new int[s.length()][t.length()];

// 初始化
if(s.charAt(0) == t.charAt(0)) dp[0][0] = 1;
else dp[0][0] = 0;

// 此时,s中仅第一个字符,判断包含t[i]的子序列个数,显然为0
for (int i = 1; i < t.length(); i++) {
dp[0][i] = 0;
}

// 此时,t中仅第一个字符判断s[i]中包含t[0]的子序列的个数,然后满足上面的状态转移方程。
for (int i = 1; i < s.length(); i++) {
if(s.charAt(i) == t.charAt(0)) dp[i][0] = dp[i-1][0] + 1;
else dp[i][0] = dp[i-1][0];
}

// 动态规划
for (int i = 1; i < s.length(); i++) {
for (int j = 1; j < t.length(); j++) {

// 注意,状态转移方程,当相同时,既可参与匹配,也可不参与匹配。。
if(s.charAt(i) == t.charAt(j)) dp[i][j] = dp[i-1][j-1] + dp[i-1][j];
else dp[i][j] = dp[i-1][j];
}
}

return dp[s.length() - 1][t.length() - 1];
}

public static void main(String[] args) {
System.out.println();

Solution_0142 s0142 = new Solution_0142();

// String s = "rabbbit";
// String t = "rabbit";

String s = "babgbag";
String t = "bag";

System.out.println(s0142.numDistinct(s, t));
}
}

3. 备注

参考力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 (leetcode-cn.com)代码随想录 (programmercarl.com)


文章作者: 浮云
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 浮云 !
  目录