原文:115. 不同的子序列(leetcode 解题) - 每天一个JavaScript小知识@Js中文网 · 码农进阶题库

原文地址:https://www.javascriptc.com/interview-tips/zh_cn/leetcode/leetcode-javascript-solution-0115/

题目:

难度:Hard

相关话题:字符串动态规划

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

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

示例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
    ^^^

思路:

DP,dp[i][j]表示[0,i]区间的t[0,j]区间的s,之间有多少个独立子序列。

设置所有dp[0][i]true,表示当t为空字符串时,总是存在1个独立子序列。

s[j-1]===t[i-1],那么dp[i][j]就是除了当前相等的两个的序列数(dp[i-1][j-1])和上一个s和当前j能匹配的序列数(dp[i][j-1])。

方程为:dp[i][j]=dp[i-1][j-1]+dp[i][j-1]

s[j-1]!==t[i-1],那么只需要将上一次s与当前j的匹配数赋值给当前dp[i][j]

方程为:dp[i][j]=dp[i][j-1]

/**
 * @来源: Javascript中文网 - 前端进阶资源教程 https://www.javascriptc.com/
 * @介绍:一个致力于帮助开发者用代码改变世界为使命的平台,每天都可以在这里找到技术世界的头条内容
 * @param {string} s
 * @param {string} t
 * @return {number}
 */
var numDistinct = function(s, t) {
  let M=t.length, N=s.length
  let dp=Array(M+1).fill().map(()=>Array(N+1).fill(0))
  for(let i=0;i<N;i++){
    dp[0][i]=1
  }
  for(let i=1;i<=M;i++){
    for(let j=1;j<=N;j++){
      let si=j-1,ti=i-1
      if(s[si]===t[ti]){
        dp[i][j]=dp[i-1][j-1]+dp[i][j-1]
      }else{
        dp[i][j]=dp[i][j-1]
      }
    }
  }
  return dp[M][N]
};

扩展阅读: