• 【LeetCode】不同的子序列 [H](动态规划)


    115. 不同的子序列 - 力扣(LeetCode)

    一、题目

    给定一个字符串 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

    提示:

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

    二、代码

    1. class Solution {
    2. public int numDistinct(String sStr, String tStr) {
    3. if (sStr == null || tStr == null || sStr.length() == 0 || tStr.length() == 0) {
    4. return 0;
    5. }
    6. char[] s = sStr.toCharArray();
    7. char[] t = tStr.toCharArray();
    8. // dp[i][j] : s只拿前i个字符做子序列,有多少个子序列,字面值等于T的前j个字符的前缀串
    9. int[][] dp = new int[s.length][t.length];
    10. // 第0行,除了dp[0][0],如果S的0下标等于T的0下标,那么dp[0][0] = 1,否则等于0。其余第0行位置都是0,因为一个字符不可能和多个字符组成的字符串相等。
    11. dp[0][0] = s[0] == t[0] ? 1 : 0;
    12. // dp[0][j] = s只拿前0个字符做子序列, T前j个字符
    13. // 从i=0开始向下遍历,只要是遍历到的格子对应的s字符串的字符位置,s的这个字符等于T字符串0下标位置的字符的话,当前格子就是上面格子的数+1,不相等,当前格子就等于上面的格子。其实就是相当于找S字符串上有多少个等于T字符串0下标的字符。
    14. for (int i = 1; i < s.length; i++) {
    15. dp[i][0] = s[i] == t[0] ? (dp[i - 1][0] + 1) : dp[i - 1][0];
    16. }
    17. // S[...i]的所有子序列中,包含多少个字面值等于T[...j]这个字符串的子序列,记为dp[i][j]
    18. // 可能性1)S[...i]的所有子序列中,都不以s[i]结尾,则dp[i][j]肯定包含dp[i-1][j]
    19. // 可能性2)S[...i]的所有子序列中,都必须以s[i]结尾,
    20. // 这要求S[i] == T[j],则dp[i][j]包含dp[i-1][j-1]
    21. for (int i = 1; i < s.length; i++) {
    22. // 不能超过t的最长范围,也不能超过此时s字符串0~i的范围长度(t字符串0~j前缀长度如果超过了s字符串0~i的长度,那么就不可能存在相等字面值的情况),所以就从i和t.length - 1中取最小值,i和t.length-1都是值的下标,所以j都是小于等于他们
    23. for (int j = 1; j <= Math.min(i, t.length - 1); j++) {
    24. // 情况1
    25. dp[i][j] = dp[i - 1][j];
    26. // 情况2
    27. if (s[i] == t[j]) {
    28. // 情况1和情况2加和
    29. dp[i][j] += dp[i - 1][j - 1];
    30. }
    31. }
    32. }
    33. return dp[s.length - 1][t.length - 1];
    34. }
    35. }

    三、解题思路 

    dp[i][j]:s字符串0...i这个范围要搞子序列,i往后范围不可使用,有多少个子序列的字面值等于字符串t从0到j这个前缀字符串。

    一共有两种情况:

    1. 子序列不考虑i位置的字符。dp[i][j] = dp[i - 1][j]
    2. 子序列一定要含有i位置的字符
    • [i]位置字符跟j位置字符不相等,那么可能性2)就一定不成立
    • [i]位置字符跟j位置字符相等,可能性2)才有可能成立。dp[i][j] = dp[i - 1][j - 1]
  • 相关阅读:
    华为云计算HCIE之oceanstor仿真器的安装教程
    【故障诊断】基于改进型的节点重构小波包频带能量谱结合概率神经网络 PNN实现轴承联合故障诊断附matlab代码
    121. 买卖股票的最佳时机
    【仿牛客网笔记】项目进阶,构建安全高效的企业服务——将文件上传至云服务器
    Android shortcuts快捷方式
    【开源】基于Vue和SpringBoot的中小学教师课程排课系统
    21天学习挑战赛--贪吃蛇
    C语言里的static变量其他语言是看不上还是学不去?
    浅谈 —— AAA认证(认证+授权)详解+配置
    【Java】抽象类和接口的区别
  • 原文地址:https://blog.csdn.net/cy973071263/article/details/127814537