子序列判断的核心逻辑是双指针贪心匹配:用两个指针分别遍历子序列和原字符串,仅当字符匹配时子序列指针才前移,确保顺序性且时间复杂度为o(n)、空间复杂度为o(1)。

子序列判断的核心逻辑是什么
子序列不要求连续,只要字符在原字符串中按顺序出现即可。比如 "ace" 是 "abcde" 的子序列,但 "aec" 不是——因为 'e' 在 'c' 之后出现,顺序被破坏了。
关键不是找所有组合,而是用双指针贪心匹配:一个指针扫源字符串,一个指针只在匹配成功时前移。时间复杂度 O(n),空间 O(1),无需额外存储或递归。
标准双指针实现(C++11+)
最直接、最不容易出错的方式是手动维护两个索引:
bool isSubsequence(const string& s, const string& t) {
int i = 0; // 指向 s(子序列候选)
for (int j = 0; j
-
s是待验证的子序列,t是主字符串 - 循环中只推进
j,仅当匹配成功才推进i - 提前退出条件(
i == s.size())可加在循环条件里,避免无谓遍历
容易踩的坑:空字符串和边界情况
-
""(空串)是任何字符串的子序列,包括自身;但 isSubsequence("a", "") 必须返回 false
- 如果不检查
i 就访问 <code>s[i],会越界(尤其 s 为空时 i=0 但 s[0] 无效)
- 错误写法:
for (char c : t) if (c == s[i]) i++ —— 这没处理 i 越界,也没提前终止
""(空串)是任何字符串的子序列,包括自身;但 isSubsequence("a", "") 必须返回 false
i 就访问 <code>s[i],会越界(尤其 s 为空时 i=0 但 s[0] 无效)
for (char c : t) if (c == s[i]) i++ —— 这没处理 i 越界,也没提前终止常见错误现象:
-
std::out_of_range异常(未检查i边界) - 对
"", "a"返回true(应为true),但对"a", ""也返回true(实际应false)
进阶:用 STL std::find_first_of 或 std::search?
别用。这两个函数语义不符:
-
std::find_first_of找的是“任意一个字符”,不是“按序匹配” -
std::search找的是子串(连续),不是子序列
真想用 STL,可配合 std::find 手动模拟双指针:
auto it = s.begin();
for (char c : t) {
if (it != s.end() && *it == c) ++it;
}
return it == s.end();
但可读性和性能都不比原始索引版本好,还引入迭代器失效风险(如传入临时 string)。
子序列判断看似简单,但边界处理和循环退出条件稍一松懈就会漏 case。最稳的还是老老实实双指针 + 显式索引控制。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











