392. 判断子序列

152 阅读2分钟

给定字符串 s 和 t ,判断 s 是否为 t 的子序列。

字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace""abcde"的一个子序列,而"aec"不是)。

进阶:

如果有大量输入的 S,称作 S1, S2, ... , Sk 其中 k >= 10亿,你需要依次检查它们是否为 T 的子序列。在这种情况下,你会怎样改变代码?

致谢:

特别感谢 ****@pbrother 添加此问题并且创建所有测试用例。

 

示例 1:

输入: s = "abc", t = "ahbgdc"
输出: true

示例 2:

输入: s = "axc", t = "ahbgdc"
输出: false

 

提示:

  • 0 <= s.length <= 100
  • 0 <= t.length <= 10^4
  • 两个字符串都只由小写字符组成。

题解:

方法一:双指针

/**
 * @param {string} s
 * @param {string} t
 * @return {boolean}
 */
// 方法一:双指针
var isSubsequence = function (s, t) {
    if (s.length == 0) return true
    let sIndex = 0;
    let tIndex = 0;
    // 以t的长度循环
    while (tIndex < t.length) {
        // 当t内有s当前index值时,s指针指向下一位。
        // 并判断s的指针长度是否和s长度相等
        if (s[sIndex] == t[tIndex]) {
            sIndex++
            if (sIndex >= s.length) {
                return true
            }
        }
        // t指针指向下一位
        tIndex++
    }
    return false;
};

方法二:动态规划

  • 1、确定dp数组以及下标的含义

dp[i][j] 表示以下标i - 1为结尾的字符串s,和以下标j - 1为结尾的字符串t,相同子序列的长度为dp[i][j]。

  • 2、确定递推公式

if (s[i - 1] == t[j - 1]) t中找到了一个字符在s中也出现了

if (s[i - 1] != t[j - 1]) 相当于t要删除元素,继续匹配

if (s[i - 1] == t[j - 1]),那么dp[i][j] = dp[i - 1][j - 1] + 1;因为找到了一个相同的字符,相同子序列长度自然要在dp[i - 1][j - 1]的基础上加1

if (s[i - 1] != t[j - 1]),此时相当于t要删除元素,t如果把当前元素t[j - 1]删除,那么dp[i][j] 的数值就是 看s[i - 1]与 t[j - 2]的比较结果了,即:dp[i][j] = dp[i][j - 1];

  • 3、dp数组如何初始化

从递推公式可以看出dp[i][j]都是依赖于dp[i - 1][j - 1]dp[i][j - 1],所以dp[0][0]和dp[i][0]是一定要初始化的。

  • 4、确定遍历顺序

从递推公式可以看出dp[i][j]都是依赖于dp[i - 1][j - 1]dp[i][j - 1],那么遍历顺序也应该是从上到下,从左到右

image.png

  • 5、举例推导dp数组

以示例一为例,输入:s = "abc", t = "ahbgdc"dp状态转移图如下:

image.png

// 方法二:动态dp
var isSubsequence = function (s, t) {
    const [m, n] = [s.length, t.length]
    // dp全初始化为0
    const dp = new Array(m + 1).fill(0).map(x => new Array(n + 1).fill(0))
    for (let i = 1; i <= m; i++) {
        for (let j = 1; j <= n; j++) {
            // 更新dp[i][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[m][n] == m ? true : false
}