Easy
题目描述
给定字符串 s 和 t ,判断 s 是否为 t 的子序列。
字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,“ace"是"abcde"的一个子序列,而"aec"不是)。
示例 1:
输入:s = "abc", t = "ahbgdc"
输出:true
示例 2:
输入:s = "axc", t = "ahbgdc"
输出:false
提示:
0 <= s.length <= 1000 <= t.length <= 10^4s和t仅由小写英文字母组成
进阶: 如果有大量输入的 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),只使用了常数额外空间 |