"子序列,那种不连续但相对顺序一致的序列"
开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第23天,点击查看活动详情
392. 判断子序列 题目描述:给定字符串 s 和 t ,判断 s 是否为 t 的子序列。字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。
| 示例1 | 示例2 |
|---|---|
输入:s = "abc", t = "ahbgdc" 输出: | 输入:s = "axc", t = "ahbgdc" 输出: |
中规中矩的动态规划
1、确定 dp 状态数组
定义 是字符串 s 在 区间与字符串 t 在 区间具有的相同子序长度,其中,,。
🎡 NOTE: 这里在 数组中预留出来一行一列作为哨兵节点。
2、确定 dp 状态方程
如果 ,说明字符串 s 在 区间与字符串 t 在 区间具体的相同子序长度,即 ,比字符串 s 在 区间与字符串 t 在 区间具体的相同子序长度,即 多 ,即,
如果 ,说明 这个元素没有任何作用,所以字符串 s 在 区间与字符串 t 在 区间具体的相同子序长度,即 ,与字符串 s 在 区间与字符串 t 在 区间具体的相同子序长度,即 ,是完全一样的,即,
3、确定 dp 初始状态
初始化整个 数组,规模 ,每个元素值为 。
4、确定遍历顺序
从 状态方程上来看, 仅依赖 与 ,所以遍历顺序可以是,
-
外层循环遍历字符串
s,从 到 ; -
内层循环遍历字符串
t,从 到 。
5、确定最终返回值
回归到状态定义中, 是字符串 s 在 区间与字符串 t 在 区间具有的相同子序长度,如果 ,那就说明 s 是 t 的子序,返回 true,否则 false。
6、代码示例
/**
* 空间复杂度 O(s.length * t.length)
* 时间复杂度 O(s.length * t.length)
*/
function isSubsequence(s: string, t: string): boolean {
const lenS = s.length;
const lenT = t.length;
const dp = Array.from({ length: lenS + 1 }, () => new Array(lenT + 1).fill(0));
for (let i = 1; i <= lenS; i++) {
for (let j = 1; j <= lenT; j++) {
if (s[i - 1] === t[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = dp[i][j - 1];
}
}
}
return dp[lenS][lenT] === lenS;
};