Intuition
Scan t left to right with a pointer into s; each time the current character of t matches the next needed character of s, advance in s. If you reach the end of s, every character was found in order.
Explanation
Idea
s is a subsequence of t when we can find every character of s inside t, in order (gaps allowed). So we greedily march through t once, and whenever the current character of t is exactly the next character of s we still need, we consume it. Being greedy is safe: matching a needed character at the earliest opportunity never blocks a later match, because any solution that skips this occurrence could use it instead.
Algorithm
- Keep an index
iintos, starting at 0 (the next character ofswe're looking for). - Walk a pointer through every character
coft:- If
i < len(s)ands[i] == c, we found the next needed character — doi += 1.
- If
- After scanning all of
t,sis a subsequence exactly wheni == len(s)(we matched every character ofs).
Worked example: s = "abc", t = "ahbgdc"
| t char | needed s[i] | action | i after |
|---|---|---|---|
| a | a | match → advance | 1 |
| h | b | no match | 1 |
| b | b | match → advance | 2 |
| g | c | no match | 2 |
| d | c | no match | 2 |
| c | c | match → advance | 3 |
i reached 3 = len(s), so every character of "abc" was found in order → true.
Complexity
- Time: O(|t|) — a single pass over
t. - Space: O(1) — just the two indices.
Implementation
class Solution {
public boolean isSubsequence(String s, String t) {
int i = 0;
for (int j = 0; j < t.length(); j++) {
if (i < s.length() && s.charAt(i) == t.charAt(j)) {
i++;
}
}
return i == s.length();
}
}