const solve = (nums) => { let left = 0, right = nums.length - 1; while (left < right) { const sum = nums[left] + nums[right]; if (sum === target) return [left, right]; }}
Problem Walkthrough

Is Subsequence LeetCode Solution: Two Pointer Walkthrough

LeetCode 392 — Is Subsequence — is the simplest two-pointer problem that teaches the fundamental difference between subsequences and substrings.

6 min read|

Two pointers, one pass, zero extra space

The simplest subsequence check that unlocks LCS, LIS, and beyond

Is Subsequence: The Simplest Subsequence Problem

Is Subsequence (#392) is one of those LeetCode problems that looks almost too easy — until you realize it encodes a concept that shows up in dozens of harder problems. The task is straightforward: given two strings s and t, determine whether s is a subsequence of t.

What makes this problem essential is not the difficulty but the distinction it forces you to understand. A subsequence maintains the relative order of characters but allows gaps. A substring (or subarray) requires contiguous elements. Confusing the two is one of the most common mistakes in coding interviews.

If you can solve Is Subsequence cleanly, you already understand the core idea behind Longest Common Subsequence (#1143), Longest Increasing Subsequence (#300), and a whole family of dynamic programming problems. This is where it all starts.

Understanding the Is Subsequence Problem

Given string s and string t, return true if s is a subsequence of t, and false otherwise. A subsequence of a string is a new string formed from the original by deleting some (or no) characters without changing the relative order of the remaining characters.

For example, "ace" is a subsequence of "abcde" because you can delete b and d to get "ace" while preserving the original order. However, "aec" is not a subsequence of "abcde" because e appears after c in the original string, but in "aec" it appears before c.

The constraints are generous: s can be up to 100 characters and t can be up to 10,000 characters. This tells you that even a linear scan through t is perfectly acceptable. No fancy optimization is needed.

Two Pointer Solution for Is Subsequence

The two-pointer approach for this problem is elegant in its simplicity. You maintain pointer i on string s and pointer j on string t. Walk through t one character at a time. Whenever t[j] matches s[i], advance both pointers. Otherwise, advance only j.

When i reaches the end of s, every character in s has been matched in order — return true. When j reaches the end of t before i finishes, some characters in s were never matched — return false. That is the entire algorithm.

The time complexity is O(n + m) where n is the length of s and m is the length of t. You scan through t at most once and s at most once. Space complexity is O(1) because you only need two integer pointers. No hash maps, no extra arrays, no recursion stack.

💡

Five-Line Solution

The two-pointer approach is 5 lines: advance j always, advance i only on match. When i reaches len(s), return true. When j reaches len(t) first, return false.

Implementation: Is Subsequence in Code

The implementation is arguably the most elegant Easy problem on LeetCode. A single while loop does all the work. There are no edge-case branches cluttering the logic — the loop naturally handles empty strings and exact matches.

Here is the approach in pseudocode: initialize i = 0 and j = 0. While both i < len(s) and j < len(t), check if s[i] equals t[j]. If they match, increment i. Always increment j. After the loop, return whether i equals len(s).

This pattern — two pointers advancing at different rates through two sequences — is a building block you will see again in merge operations, linked list problems, and string matching. Recognizing it here makes those harder problems feel familiar.

  • Initialize two pointers i = 0 (for s) and j = 0 (for t)
  • While i < len(s) and j < len(t): if s[i] == t[j], increment i; always increment j
  • Return i == len(s) — if true, all characters of s were matched in order
  • Time: O(n + m) — single pass through both strings
  • Space: O(1) — only two integer variables

Visual Walkthrough: Is Subsequence Examples

Let us trace through s = "ace" and t = "abcde". Start with i = 0, j = 0. t[0] = "a" matches s[0] = "a", so advance both: i = 1, j = 1. t[1] = "b" does not match s[1] = "c", so advance only j: j = 2. t[2] = "c" matches s[1] = "c", advance both: i = 2, j = 3. t[3] = "d" does not match s[2] = "e", advance j: j = 4. t[4] = "e" matches s[2] = "e", advance both: i = 3, j = 5. Now i = 3 = len(s), return true.

Now trace s = "aec" and t = "abcde". Start i = 0, j = 0. "a" matches "a": i = 1, j = 1. "b" does not match "e": j = 2. "c" does not match "e": j = 3. "d" does not match "e": j = 4. "e" matches "e": i = 2, j = 5. Now j = 5 = len(t), but i = 2 and s[2] = "c" was never matched. Return false.

The second example is the key insight. Even though all three characters a, e, and c exist in t, the order is wrong — c appears before e in t, but after e in s. The two-pointer approach catches this naturally because it only moves forward through both strings.

⚠️

Order Matters

Don't confuse subsequence with substring — 'ace' is a subsequence of 'abcde' (skip b,d) but 'aec' is NOT (c comes before e in t). Order must be preserved.

Edge Cases for Is Subsequence

The beauty of the two-pointer solution is that edge cases resolve themselves without special handling. When s is empty, the while loop never executes because i = 0 already equals len(s) = 0, so the function returns true immediately. An empty string is a subsequence of every string.

When s is longer than t, the loop exits when j reaches the end of t, and i will still be less than len(s). The function returns false. When s equals t exactly, every character matches on the first comparison, and both pointers advance together to the end.

  • s is empty → true (empty string is a subsequence of anything)
  • s is longer than t → false (cannot be a subsequence of a shorter string)
  • s equals t → true (exact match, every character aligns)
  • No characters of s appear in t → false (i never advances)
  • Single character s → true if that character exists anywhere in t

What Is Subsequence Teaches You

This problem crystallizes the difference between subsequence and substring — a distinction that trips up candidates in problems like Longest Common Subsequence (#1143), Longest Increasing Subsequence (#300), and Distinct Subsequences (#115). If you truly understand why "aec" fails on "abcde", you will not confuse these concepts again.

The two-pointer technique on two different strings is a pattern you will reuse repeatedly. Merge two sorted arrays, compare version numbers, and interleave strings all use the same idea: two pointers advancing at independent rates through separate sequences.

Is Subsequence is also the perfect warm-up problem for understanding the follow-up question posed in LeetCode 392 itself: what if there are many s strings to check against the same t? That leads to binary search preprocessing — a natural next step once the basic two-pointer idea clicks. Drill this pattern with YeetCode flashcards and the foundation will stick.

ℹ️

Foundation Problem

Is Subsequence (#392) is the foundational problem for understanding subsequences — it clarifies that subsequences maintain order but skip elements, unlike substrings which must be contiguous.

Ready to master algorithm patterns?

YeetCode flashcards help you build pattern recognition through active recall and spaced repetition.

Start practicing now