不同的子序列

104 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

题目描述

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

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

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

示例 1

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

示例 2

输入:s = "babgbag", t = "bag"
输出:5
解释:
如下图所示, 有 5 种可以从 s 中得到 "bag" 的方案。 
babgbag
babgbag
babgbag
babgbag
babgbag

思路分析

  • 当遇到字符串匹配相关问题时,我们可能会想到滑动窗口、动态规划等等。本题目要求在 ss 串中找出可以组成 tt 串的数量。所以可以以 tt 串的每个字符为基准,它对应的 ss 串的字符有相同和不相同两种状态,可以根据前一状态进行转移到当前状态。
  • 假设 tt 对应位置为 iiss 对应位置为 jj
  1. 当对应位置字符 相同 时,我们只需要把 s[0,j1]s[0,j - 1]t[0,i]t[0,i] 子串的数量加上 s[0,j1]s[0,j - 1]t[0,i1]t[0,i - 1] 子串的数量转移到当前状态。表达式为:dp[i][j]=dp[i1][j1]+dp[i][j1]dp[i][j] = dp[i - 1][j - 1] + dp[i][j - 1]
  2. 当对应位置字符 不相同 时,只需把 s[0,j1]s[0,j - 1]t[0,i]t[0,i] 子串数量转移到当前状态。表达式为:dp[i][j]=dp[i][j1]dp[i][j] = dp[i][j - 1]

AC 代码

class Solution {
    public int numDistinct(String s, String t) {
        char[] cs = s.toCharArray();
        char[] ct = t.toCharArray();
        int ns = cs.length;
        int nt = ct.length;
        int[][] dp = new int[nt + 1][ns + 1];
        Arrays.fill(dp[0],1);
        for (int i = 1; i <= nt; i++) {
            for (int j = 1; j <= ns; j++) {
                if (ct[i - 1] == cs[j - 1]) {
                    dp[i][j] = dp[i][j - 1] + dp[i - 1][j - 1];
                } else {
                    dp[i][j] = dp[i][j - 1];
                }
            }
        }
        return dp[nt][ns];
    }
}

总结

  • 动态规划的题就是这样,当想明白的时候,题目就 AC 得很快,反之不然。如果还有疑问的话可以点击 这里