Easy

题目描述

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

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

示例 1:

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

示例 2:

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

提示:

  • 0 <= s.length <= 100
  • 0 <= t.length <= 10^4
  • st 仅由小写英文字母组成

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

解题思路

这道题可以用多种方法解决:

方法一:双指针(推荐) 最直观的解法是使用双指针,一个指向字符串 s,一个指向字符串 t。我们从左到右遍历字符串 t,当找到与 s 中当前字符匹配的字符时,移动 s 的指针。如果 s 的指针能够遍历完整个字符串,说明 s 是 t 的子序列。

方法二:动态规划 可以用 DP 解决,但对于此题来说过于复杂,时间复杂度相同但空间复杂度更高。

方法三:预处理优化(针对进阶问题) 对于进阶问题中需要处理大量查询的情况,可以预处理字符串 t,为每个位置记录下一个各字符的位置,这样可以将单次查询的时间复杂度降低到 O(|s|)。

本题推荐使用双指针解法,代码简洁且效率最高。

代码实现

class Solution {
public:
    bool isSubsequence(string s, string t) {
        int i = 0, j = 0;
        while (i < s.length() && j < t.length()) {
            if (s[i] == t[j]) {
                i++;
            }
            j++;
        }
        return i == s.length();
    }
};
class Solution:
    def isSubsequence(self, s: str, t: str) -> bool:
        i = j = 0
        while i < len(s) and j < len(t):
            if s[i] == t[j]:
                i += 1
            j += 1
        return i == len(s)
public class Solution {
    public bool IsSubsequence(string s, string t) {
        int i = 0, j = 0;
        while (i < s.Length && j < t.Length) {
            if (s[i] == t[j]) {
                i++;
            }
            j++;
        }
        return i == s.Length;
    }
}
var isSubsequence = function(s, t) {
    let i = 0, j = 0;
    while (i < s.length && j < t.length) {
        if (s[i]

复杂度分析

复杂度大小
时间复杂度O(n + m),其中 n 是字符串 s 的长度,m 是字符串 t 的长度
空间复杂度O(1),只使用了常数额外空间

相关题目