「这是我参与2022首次更文挑战的第23天,活动详情查看:2022首次更文挑战」。
题目
链接:leetcode-cn.com/problems/di…
给定一个字符串 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 <= 1000s和t由英文字母组成
思路
给定一个字符串 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 tabledp[i][j]表示s[0-i]的子序列 与t[0-j]相等的个数
- 定义
dp方程if (s[i] !== t[j])- 此时
dp[i][j]等价于dp[i - 1][j],所以dp[i][j] = dp[i - 1][j]
- 此时
if (s[i] === t[j])那么这时要分为两种情况,选不选s[i]作为s[0-i]子序列的最后一个字符- 选,那么
dp[i][j] = dp[i - 1][j - 1] - 不选,那么
dp[i][j] = dp[i - 1][j] - 综上,
dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j]
- 选,那么
dp table初始化- 在
s、t字符串的前面加上一个空字符串,将dp初始化成s.length + 1*t.length + 1的二维数组,并将所有的值全部初始化为0 - 当
j = 0时,t为空字符串,则dp[i][0] = 1
- 在
- 结果
return dp[s.length][t.length]
代码
/**
* @param {string} s
* @param {string} t
* @return {number}
*/
var numDistinct = function(s, t) {
let dp = Array.from({length: s.length + 1}, _ => Array(t.length + 1).fill(0));
for (let i = 0; i <= s.length; i++) dp[i][0] = 1;
for (let i = 1; i <= s.length; i++) {
for (let j = 1; j <= t.length; j++) {
if (s[i - 1] === t[j - 1]) {
dp[i][j] = dp[i - 1][j] + dp[i - 1][j -1]
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
return dp[s.length][t.length];
};
时间复杂度: O(M * N),M 为字符串 s 的长度,N 为字符串 t 的长度
空间复杂度: O(M * N),M 为字符串 s 的长度,N 为字符串 t 的长度