【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]
  • 相等时,还需要加上不考虑st的当前字母的情况。

解答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];
    }
};
posted @ 2021-04-06 10:41  tmpUser  阅读(45)  评论(0编辑  收藏  举报