🌈【LeetCode 115. 不同的子序列 】- JavaScript(动态规划)

104 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天,点击查看活动详情


说明:文章部分内容及图片出自网络,如有侵权请与我本人联系(主页有公众号:小攻城狮学前端)

作者:小只前端攻城狮、 主页:小只前端攻城狮的主页、 来源:掘金

GitHub:P-J27、 CSDN:PJ想做前端攻城狮

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


【LeetCode 115. 不同的子序列 】- JavaScript(动态规划)

题目描述

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

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

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

示例 1:

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

动态规划

思路分析:

整体的的思路:分析完题目就知道这又是一个动态规划的题目,这种字符串,子序列的问题,肯定是上来就想DP怎么解,如果DFS 肯定是超时的解法,不过可以从DFS的过程中总结自己DP的状态方程。真的是我的噩梦啊,但是还是得做,呜呜呜。构建dp数组,dp[i][j]表示t的前i个序列在s的前j个序列出现的次数,为了方便第一行和第一列容易操作,增加了空字符对应的数据,那么可以总结出规律:

  • 当前结束位字符相同,可以组合出新的子串:dp[i][j] = dp[i][j - 1] + dp[i - 1][j - 1];
  • 当前结束位不相同,那么子串数量就是前一个值:dp[i][j] = dp[i][j - 1];

对于上述的状态方程的理解如下

  • 当s[j]==t[i]时,dp[i][j]表示s前j个匹配前i个元素的个数
  • 所以dp[i][j]包含两部分,之前匹配的-dp[i-1][j] + 新增的-s[j]匹配t[i]
  • 可以看出新增的个数就等于dp[i-1][j-1]也就是匹配t前i-1个元素的个数
var numDistinct = function (s, t) {
    const m = s.length, n = t.length;
    if (m < n) {
        return 0;
    }
    const dp = new Array(n + 1).fill(0).map(() => new Array(m + 1).fill(0));
    for (let i = 0; i <= m; i++) {
        dp[0][i] = 1;
    }
    for (let i = 1; i <= n; i++) {
        for (let j = 1; j <= m; j++) {
            if (t[i - 1] === s[j - 1]) {
                dp[i][j] = dp[i][j - 1] + dp[i - 1][j - 1];
            } else {
                dp[i][j] = dp[i][j - 1];
            }
        }
    }
    return dp[n][m];
};

思考

注意点:虽然我很菜,做题就像个弟弟,但我的个人也做过很多个串的题,虽然我不一定能推出来,但是我能猜出来动态方程。不是dp[i-1][j-1]就是dp[i-1][j]这类的,不知道这是好是坏呢


感谢阅读,希望能对你有所帮助,文章若有错误或者侵权,可以在评论区留言或在我的主页添加公众号联系我。

写作不易,如果觉得不错,可以「点赞」+「评论」 谢谢支持❤