392. 判断子序列 (is subsequence)

3,815 阅读2分钟

"子序列,那种不连续但相对顺序一致的序列"

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第23天,点击查看活动详情

392. 判断子序列 题目描述:给定字符串 s 和 t ,判断 s 是否为 t 的子序列。字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace""abcde"的一个子序列,而"aec"不是)。

示例1示例2
输入s = "abc", t = "ahbgdc"
输出truetrue
输入s = "axc", t = "ahbgdc"
输出falsefalse

中规中矩的动态规划

1、确定 dp 状态数组

定义 dp[i][j]dp[i][j] 是字符串 s[0,i)[0, i) 区间与字符串 t[0,j)[0, j) 区间具有的相同子序长度,其中,i[0,lens),j[0,lent)i \in [0, len_s),j \in [0, len_t)lens=s.length,lent=t.lengthlen_s=s.length,len_t=t.length

🎡 NOTE: 这里在 dpdp 数组中预留出来一行一列作为哨兵节点。

2、确定 dp 状态方程

如果 s[i1]==t[j1]s[i - 1] == t[j - 1],说明字符串 s[0,i)[0, i) 区间与字符串 t[0,j)[0, j) 区间具体的相同子序长度,即 dp[i][j]dp[i][j],比字符串 s[0,i1)[0, i-1) 区间与字符串 t[0,j1)[0, j-1) 区间具体的相同子序长度,即 dp[i1][j1]dp[i - 1][j - 1]11,即,

dp[i][j]=dp[i1][j1]+1dp[i][j] = dp[i - 1][j - 1] + 1

如果 s[i1]!=t[j1]s[i - 1] != t[j - 1],说明 t[j1]t[j - 1] 这个元素没有任何作用,所以字符串 s[0,i)[0, i) 区间与字符串 t[0,j)[0, j) 区间具体的相同子序长度,即 dp[i][j]dp[i][j],与字符串 s[0,i)[0, i) 区间与字符串 t[0,j1)[0, j-1) 区间具体的相同子序长度,即 dp[i][j1]dp[i][j-1],是完全一样的,即,

dp[i][j]=dp[i][j1]dp[i][j] = dp[i][j - 1]

3、确定 dp 初始状态

初始化整个 dpdp 数组,规模 (lens+1)×(lent+1)(len_s+1) \times (len_t+1),每个元素值为 00

4、确定遍历顺序

dpdp 状态方程上来看,dp[i][j]dp[i][j] 仅依赖 dp[i1][j1]dp[i-1][j-1]dp[i][j1]dp[i][j-1] ,所以遍历顺序可以是,

  • 外层循环遍历字符串 s,从 i=1i = 1i=lensi = len_s

  • 内层循环遍历字符串 t,从 j=1j = 1j=lentj = len_t

5、确定最终返回值

回归到状态定义中,dp[i][j]dp[i][j] 是字符串 s[0,i)[0, i) 区间与字符串 t[0,j)[0, j) 区间具有的相同子序长度,如果 dp[i][j]==lensdp[i][j] == len_s,那就说明 st 的子序,返回 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;
};

参考

# 重识动态规划