不同的子序列

186 阅读1分钟

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

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

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

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

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

示例 1:

输入: s = "rabbbit", t = "rabbit"
**输出**3
解释:
如下图所示, 有 3 种可以从 s 中得到 "rabbit" 的方案
**rabb**b**it**
**ra**b**bbit**
**rab**b**bit**

示例 2:

输入: s = "babgbag", t = "bag"
**输出**5
解释:
如下图所示, 有 5 种可以从 s 中得到 "bag" 的方案
**ba**b**g**bag
**ba**bgba**g**
**b**abgb**ag**
ba**b**gb**ag**
babg**bag**

提示:

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

思路

mn来表示st的长度,本题分为三种情况:

  • 如果s等于t,返回1
  • 如果m小于等于n,返回0
  • 如果m大于n,用动态规划求解。用数组dp[i][j]来保存s中前i个字符的子序列在t的前j个字符中出现的个数,则
    • 如果s[i-1]不等于t[j-1]dp[i][j] = dp[i-1][j]
    • 如果s[i-1]等于t[j-1]dp[i][j] = dp[i-1][j] + dp [i-1][j-1]
      最后返回dp[m][n],初始状态dp[0][0] = 1,表示初始值两个空字符串匹配个数为1

解题

/**
 * @param {string} s
 * @param {string} t
 * @return {number}
 */
var numDistinct = function (s, t) {
  if (s === t) return 1;
  const m = s.length;
  const n = t.length;
  if (m <= n) return 0;
  const dp = new Array(n + 1).fill(null).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++) {
      dp[i][j] = dp[i][j - 1];
      if (t[i - 1] === s[j - 1]) {
        dp[i][j] += dp[i - 1][j - 1];
      }
    }
  }
  return dp[n][m];
};