【LeetCode-115】不同的子序列
问题
给定一个字符串 s 和一个字符串 t ,计算在 s 的子序列中 t 出现的个数。
字符串的一个 子序列 是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串。(例如,"ACE" 是 "ABCDE" 的一个子序列,而 "AEC" 不是)
题目数据保证答案符合 32 位带符号整数范围。
示例
输入: S = "babgbag", T = "bag"
输出: 5
解释:
如下图所示, 有 5 种可以从 S 中得到 "bag" 的方案。
(上箭头符号 ^ 表示选取的字母)
babgbag
^^ ^
babgbag
^^ ^
babgbag
^ ^^
babgbag
^ ^^
babgbag
^^^
解答1:动态规划
class Solution {
public:
int numDistinct(string s, string t) {
int m = s.size(), n = t.size();
long dp[m + 1][n + 1]; bzero(dp, sizeof dp);
for (int i = 0; i <= m; i++) dp[i][0] = 1;
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
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];
}
};
重点思路
看见双字符串问题第一时间就应该想到用动态规划的方法解。对于此类问题,一般都需要讨论dp[i][j]
与dp[i - 1][j]
、dp[i][j - 1]
、dp[i - 1][j - 1]
的关系,根据s[i - 1]
与t[j - 1]
之间的关系分类讨论。
本题按照s[i - 1]
与t[j - 1]
是否相等分为两种情况:
- 不相等时,只需将
s
字符串中前一个字母前的子字符串与当前t
的匹配子序列数量传给当前dp即可,即dp[i][j] = dp[i - 1][j]
; - 相等时,还需要加上不考虑
s
与t
的当前字母的情况。
解答2:动态规划(状态压缩)
class Solution {
public:
int numDistinct(string s, string t) {
int m = s.size(), n = t.size();
long dp[2][n + 1]; bzero(dp, sizeof dp);
for (int i = 0; i < 2; i++) dp[i][0] = 1;
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
dp[i & 1][j] = dp[(i - 1) & 1][j];
if (s[i - 1] == t[j - 1]) dp[i & 1][j] += dp[(i - 1) & 1][j - 1];
}
}
return dp[m & 1][n];
}
};