Hi👋SpeedAlgo • Deliberate Practice & Cognitive Ergonomics for Software Engineers

An interactive algorithm mastery and technical interview preparation platform published by Hi👋WebEnterprise. Built for senior and staff software engineers preparing for rigorous coding screens at top tech companies (FAANG/MAMAA).

13 Core Algorithmic Patterns & 225 Practice Problems

  • 1. Two Pointers (16 Paradigms, 43 Problems): Opposite ends, sorted pair sums, palindrome verification, trapping rain water, 3Sum, container with most water — includes the Sliding Window and Fast & Slow Pointers paradigms (contiguous subarray invariants, longest substrings, Floyd's cycle detection, linked list middle).
  • 2. Binary Search (9 Paradigms, 14 Problems): Monotonic predicate partitioning (feasible(x)), boundary search, rotated sorted arrays, square roots, minimum ship capacity, median of two sorted arrays, matrix median on value range.
  • 3. Bit Manipulation (5 Paradigms, 11 Problems): Counting set bits, XOR cancellation, bit reversal, bitmask pairing, maximum XOR with a bitwise trie.
  • 4. Math & Geometry (8 Paradigms, 14 Problems): Sieve of Eratosthenes, integer/roman conversions, modular arithmetic, geometric simulation.
  • 5. Tree/Graph Depth-First Search (15 Paradigms, 24 Problems): Path sums, lowest common ancestor, tree diameter, validating BSTs, tree DP (House Robber III, Binary Tree Cameras).
  • 6. Tree/Graph Breadth-First Search (5 Paradigms, 12 Problems): Level-order traversals, shortest path in unweighted graphs, zig-zag traversals, rotting oranges, word ladders.
  • 7. Graphs (12 Paradigms, 22 Problems): Topological sort, cycle detection, Dijkstra's algorithm, bipartite graph validation, network delay.
  • 8. Backtracking (6 Paradigms, 14 Problems): Subsets, permutations, combinations, constraint satisfaction, pruning, N-Queens, Sudoku solver.
  • 9. Dynamic Programming (13 Paradigms, 28 Problems): Memoization vs tabulation, 0/1 knapsack, unbounded knapsack, coin change, edit distance, longest common subsequence.
  • 10. Heap / Priority Queue (9 Paradigms, 11 Problems): Running medians, top-k elements, interval scheduling, IPO, k-way merges.
  • 11. Advanced Data Structures (7 Paradigms, 17 Problems): Trie (prefix tree), Union-Find (Disjoint Set Union), LRU Cache, LFU Cache, range-sum queries with updates.
  • 12. Stack (5 Paradigms, 9 Problems): Next greater element, largest rectangle in histogram, remove k digits, decode string, min stack.
  • 13. Intervals & Greedy (2 Paradigms, 6 Problems): Merge intervals, interval scheduling, meeting rooms by sweep line, jump game.

4-Stage Deliberate Practice Framework

  1. Stage 1 (Compare & Learn): Read the pattern's mental model, loop invariant and Big-O proof, compare the pattern's template with the problem's solution side by side, and use the step-by-step debugger. The solution can also be shown in C#, Java, TypeScript, C++, Go or Rust for almost every problem.
  2. Stage 2 (Active Recall): Rebuild the solution from memory in a code editor, with an invariant checklist and optional progressive hints, and check it against a judged test suite.
  3. Stage 3 (AI Interview Coach, coming soon): A mock-interview stage still in development; for now, students go straight from Stage 2 to Stage 4.
  4. Stage 4 (Solve on Your Own): Solve a new problem on your own against a 15-minute timer; your code is graded against a test suite. Python and TypeScript run in your browser and C# runs on our server (design problems grade in Python and TypeScript).

Equipped with a spaced-repetition review hub on a fixed 7-step schedule (1 day up to 90 days), a two-pane Studio workspace, and study notes.

Pricing, Access & Commercial Terms

  • Core Curriculum: 100% Free. No credit card required.
  • Coins: New accounts get 40 free coins once, the daily claim adds +20 coins once a day, and inviting a friend earns you +25 coins when they complete their first practice step. These are the only ways to earn coins.
  • AI Coach: Each AI coach question costs 1-5 coins, priced by the server according to its size.
  • BYOK (Bring Your Own Key): AI coaching is free with your own Google Gemini, OpenAI or OpenRouter API key (BYOK).
  • Extras: Coins also unlock extras for 24 hours: a Recall hint level (1 coin), a Solve solution reveal (2), a LeetCode problem card's solutions (1) and a pattern's extra canonical problems (1).
  • Payments & Refunds: Nothing on the site is sold for money: coins can only be earned, never bought. There are no subscriptions or charges, so there is nothing to refund.
  • Platform Operator: Hi👋WebEnterprise. Support & policies at hispeedalgo.com.
Skip to main content
Hi👋SpeedAlgo

Invariant-First Algorithmic Mastery

Arena
238Items
Theory Context•Two Pointers & Sliding Window
EasyLC 392

Is Subsequence (LeetCode 392)

Target Frequency:AmazonGooglePinterest

You get two strings, s and t. Decide whether s is a subsequence of t: whether every character of s appears somewhere in t, in the same relative order, though not necessarily next to each other. Return true or false.

Worked Examples

Example 1
Input:s = "abc", t = "ahbgdc"
Output:true
Explanation: a, b and c appear in t at positions 0, 2 and 5, in that order.
Example 2
Input:s = "axc", t = "ahbgdc"
Output:false
Explanation: t has no x at all, so s cannot be picked out of it.

⚖️Formal Constraints & Bounds

  • 0 <= s.length <= 100

  • 0 <= t.length <= 104

  • s and t consist only of lowercase English letters.

Deep-Dive & Conceptual Insights

Core Insight

Walking t once and claiming the next unclaimed character of s the moment it is seen always finds a match if one exists, because the earliest available match for any character of s never costs a later character of s its own match.

Real-World Scenario & Production Applications

Checking whether a sequence of required approvals (s) all happened, in order, somewhere inside a longer audit log (t) is the same claim: walk the log once, and tick off the next required approval the moment it appears, regardless of what else happened around it.

Step-by-Step Execution Trace Table

Input s = "abc", t = "ahbgdc" (LeetCode Example 1). i = 0 at the start:

jt[j]s[i] (if i < len(s))Match?i after this step
0aaYes1
1hbNo1
2bbYes2
3gcNo2
4dcNo2
5ccYes3
Endi == len(s) == 3, so the function returns true
Code Shape
Archetype Code Shape
Python
1Give s its own claimed-count pointer, i, starting at 0.
2Walk t once with j; advance i only when t[j] equals s[i], the next unclaimed character of s.
3`i = 0`; `for j in range(len(t)): if i < len(s) and s[i] == t[j]: i += 1`; `return i == len(s)`.
4The trap: advancing i on every character of t, not only on a match, makes the final check pass even when s is not really a subsequence of t.

Conceptual Narrative

🧭 Conceptual Foundation & Pattern Intuition

Deciding whether every character of a short string s shows up, in order, somewhere inside a longer string t looks like it needs backtracking or a search over which characters of t to skip, but it does not: walking t once and greedily claiming the next unclaimed character of s the moment it appears always finds a match if one exists. Claiming the earliest available copy of a character is never a mistake, because every later position of t is still free for whatever comes next in s -- a later choice would only leave less of t behind.

🧾 The Analogy: Checking Off a Shopping List While Walking Down One Aisle

Picture a short shopping list, s, and one long aisle of shelves, t, read start to end exactly once. Walk the aisle item by item; the moment the item in front of you matches the next item still unchecked on the list, check it off. Skip every shelf that does not match the next item you need -- it costs nothing to skip, and you never walk the aisle a second time to look for an item you have already found. By the end of the aisle, the list is fully satisfied exactly when every item on it has been checked off, in order.

🔑 Why It Works

Checking off the earliest copy of the next needed item is always at least as good as waiting for a later copy: every shelf after the one just checked off is still available for the rest of the list, so an earlier claim can never cost a later one. Across the whole walk, j visits every character of t exactly once, and i only ever moves forward, so the whole decision costs one pass over t, O(len(t)).

  • Advancing i on every character of t, not only on a match (the card's trap): moving i += 1 outside the if claims characters that were never actually matched, so the final check i == len(s) can say true even when s is not really a subsequence of t.

  • Writing i == len(s) - 1 instead of i == len(s): i reaches len(s) only once every character of s is claimed; comparing against len(s) - 1 rejects a correct full match one claim too early.

  • Checking s[i] in t instead of walking t in order: membership alone has no memory of how far through t the previous match reached, so it can accept characters of s matched out of order.

  • Treating Append Characters to String to Make Subsequence (LC 2486) as a new algorithm: it is the same claim run the other way -- walk s once, claim characters of t, and the answer is len(t) minus the number claimed, since the rest can always be appended to the end of s.

  • Subtracting from the wrong length on LC 2486's transfer problem: the answer is len(t) - claimed, not len(s) - claimed; s is the string being walked, t is the string being claimed.

Senior SWE Reasoning Architecture

4-Phase Thought Process Model

Pattern Recognition Signals

The 10-second spot

Two strings, s and t, and the question is whether every character of s appears in t in the same relative order, though not necessarily next to each other. The order matters but the gaps do not, so one forward walk over t can answer it. That is the signal for Greedy Subsequence Match: walk t once and claim the next unclaimed character of s each time it appears.

Formulating the Predicate & Invariants

Turning intuition into a boolean rule

i counts how many characters of s are claimed so far, in order. At each t[j], i goes up by one only when i < len(s) and s[i] == t[j]. The earliest available match for s[i] never costs a later character of s its own match, so i == len(s) after the walk means s is a subsequence of t.

Silent Failure Traps & Edge Cases

Where confident candidates still lose points

  • Returning true as soon as the scan of t finishes, instead of checking i: reaching the last index of t only means the walk is over, not that every character of s was claimed.

The 60-Second Interview Pitch

Say this out loud before you type a single line

I'd use Greedy Subsequence Match. I walk t once with j and keep i, the number of characters of s that I have already claimed in order. At each j, if i is still inside s and s at i equals t at j, I advance i by one; otherwise I leave i alone. Taking the earliest available match is always safe, because every later position of t is still free for whatever comes next in s. When the walk ends, s is a subsequence of t exactly when i equals the length of s. The trap is advancing i on every character of t, not only on a match: that claims characters that were never matched, so the final check can say true when it should say false. The walk is O(len(t)) time and O(1) space.

Big-O Invariant Derivation

Complexity & Mathematical Proof

TIME COMPLEXITY

O(len(t))

The for loop runs once over t; each iteration does one comparison and, at most, one increment of i.

SPACE COMPLEXITY

O(1)

Nothing is allocated beyond the two integer counters i and j.

Pointer Invariant Transition Progression

Pointer Invariant Transition Progression
Synthesizing vector architecture diagram...
Staff+ Engineering Perspective

Senior SWE Deconstruction & Hardware Caveats

ARCHITECTURAL SIGNALS & INTERVIEW TRIGGERS

Triggers: "is s a subsequence of t", "deleting some characters", "keep the rest in their original order". One short string checked against one long string, order preserved but gaps allowed: Greedy Subsequence Match, a single pass claiming characters greedily.

CONSTRAINTS & BOUNDS

0≤s.length≤1000 \le s.length \le 1000≤s.length≤100, 0≤t.length≤1040 \le t.length \le 10^40≤t.length≤104. Budget: O(len(t))O(len(t))O(len(t)) time, O(1)O(1)O(1) space -- one pass over the longer string, no extra memory beyond two counters.

FAANG PRODUCTION TRAPS & EDGE CASES

Advancing i on every character of t, not only on a match, lets the final check pass even when s is not really a subsequence of t. The follow-up (many strings checked against the same t) changes the cost model: indexing t's letter positions once and binary-searching them per query turns many single-pass scans into one O(n log n) build plus O(m log n) per query, where this card's own approach alone would cost O(q * len(t)) across q queries.

Theory Context•Two Pointers & Sliding Window
EasyLC 392

Is Subsequence (LeetCode 392)

Target Frequency:AmazonGooglePinterest

You get two strings, s and t. Decide whether s is a subsequence of t: whether every character of s appears somewhere in t, in the same relative order, though not necessarily next to each other. Return true or false.

Worked Examples

Example 1
Input:s = "abc", t = "ahbgdc"
Output:true
Explanation: a, b and c appear in t at positions 0, 2 and 5, in that order.
Example 2
Input:s = "axc", t = "ahbgdc"
Output:false
Explanation: t has no x at all, so s cannot be picked out of it.

⚖️Formal Constraints & Bounds

  • 0 <= s.length <= 100

  • 0 <= t.length <= 104

  • s and t consist only of lowercase English letters.

Deep-Dive & Conceptual Insights

Core Insight

Walking t once and claiming the next unclaimed character of s the moment it is seen always finds a match if one exists, because the earliest available match for any character of s never costs a later character of s its own match.

Real-World Scenario & Production Applications

Checking whether a sequence of required approvals (s) all happened, in order, somewhere inside a longer audit log (t) is the same claim: walk the log once, and tick off the next required approval the moment it appears, regardless of what else happened around it.

Step-by-Step Execution Trace Table

Input s = "abc", t = "ahbgdc" (LeetCode Example 1). i = 0 at the start:

jt[j]s[i] (if i < len(s))Match?i after this step
0aaYes1
1hbNo1
2bbYes2
3gcNo2
4dcNo2
5ccYes3
Endi == len(s) == 3, so the function returns true
Code Shape
Archetype Code Shape
Python
1Give s its own claimed-count pointer, i, starting at 0.
2Walk t once with j; advance i only when t[j] equals s[i], the next unclaimed character of s.
3`i = 0`; `for j in range(len(t)): if i < len(s) and s[i] == t[j]: i += 1`; `return i == len(s)`.
4The trap: advancing i on every character of t, not only on a match, makes the final check pass even when s is not really a subsequence of t.

Conceptual Narrative

🧭 Conceptual Foundation & Pattern Intuition

Deciding whether every character of a short string s shows up, in order, somewhere inside a longer string t looks like it needs backtracking or a search over which characters of t to skip, but it does not: walking t once and greedily claiming the next unclaimed character of s the moment it appears always finds a match if one exists. Claiming the earliest available copy of a character is never a mistake, because every later position of t is still free for whatever comes next in s -- a later choice would only leave less of t behind.

🧾 The Analogy: Checking Off a Shopping List While Walking Down One Aisle

Picture a short shopping list, s, and one long aisle of shelves, t, read start to end exactly once. Walk the aisle item by item; the moment the item in front of you matches the next item still unchecked on the list, check it off. Skip every shelf that does not match the next item you need -- it costs nothing to skip, and you never walk the aisle a second time to look for an item you have already found. By the end of the aisle, the list is fully satisfied exactly when every item on it has been checked off, in order.

🔑 Why It Works

Checking off the earliest copy of the next needed item is always at least as good as waiting for a later copy: every shelf after the one just checked off is still available for the rest of the list, so an earlier claim can never cost a later one. Across the whole walk, j visits every character of t exactly once, and i only ever moves forward, so the whole decision costs one pass over t, O(len(t)).

  • Advancing i on every character of t, not only on a match (the card's trap): moving i += 1 outside the if claims characters that were never actually matched, so the final check i == len(s) can say true even when s is not really a subsequence of t.

  • Writing i == len(s) - 1 instead of i == len(s): i reaches len(s) only once every character of s is claimed; comparing against len(s) - 1 rejects a correct full match one claim too early.

  • Checking s[i] in t instead of walking t in order: membership alone has no memory of how far through t the previous match reached, so it can accept characters of s matched out of order.

  • Treating Append Characters to String to Make Subsequence (LC 2486) as a new algorithm: it is the same claim run the other way -- walk s once, claim characters of t, and the answer is len(t) minus the number claimed, since the rest can always be appended to the end of s.

  • Subtracting from the wrong length on LC 2486's transfer problem: the answer is len(t) - claimed, not len(s) - claimed; s is the string being walked, t is the string being claimed.

Senior SWE Reasoning Architecture

4-Phase Thought Process Model

Pattern Recognition Signals

The 10-second spot

Two strings, s and t, and the question is whether every character of s appears in t in the same relative order, though not necessarily next to each other. The order matters but the gaps do not, so one forward walk over t can answer it. That is the signal for Greedy Subsequence Match: walk t once and claim the next unclaimed character of s each time it appears.

Formulating the Predicate & Invariants

Turning intuition into a boolean rule

i counts how many characters of s are claimed so far, in order. At each t[j], i goes up by one only when i < len(s) and s[i] == t[j]. The earliest available match for s[i] never costs a later character of s its own match, so i == len(s) after the walk means s is a subsequence of t.

Silent Failure Traps & Edge Cases

Where confident candidates still lose points

  • Returning true as soon as the scan of t finishes, instead of checking i: reaching the last index of t only means the walk is over, not that every character of s was claimed.

The 60-Second Interview Pitch

Say this out loud before you type a single line

I'd use Greedy Subsequence Match. I walk t once with j and keep i, the number of characters of s that I have already claimed in order. At each j, if i is still inside s and s at i equals t at j, I advance i by one; otherwise I leave i alone. Taking the earliest available match is always safe, because every later position of t is still free for whatever comes next in s. When the walk ends, s is a subsequence of t exactly when i equals the length of s. The trap is advancing i on every character of t, not only on a match: that claims characters that were never matched, so the final check can say true when it should say false. The walk is O(len(t)) time and O(1) space.

Big-O Invariant Derivation

Complexity & Mathematical Proof

TIME COMPLEXITY

O(len(t))

The for loop runs once over t; each iteration does one comparison and, at most, one increment of i.

SPACE COMPLEXITY

O(1)

Nothing is allocated beyond the two integer counters i and j.

Pointer Invariant Transition Progression

Pointer Invariant Transition Progression
Synthesizing vector architecture diagram...
Staff+ Engineering Perspective

Senior SWE Deconstruction & Hardware Caveats

ARCHITECTURAL SIGNALS & INTERVIEW TRIGGERS

Triggers: "is s a subsequence of t", "deleting some characters", "keep the rest in their original order". One short string checked against one long string, order preserved but gaps allowed: Greedy Subsequence Match, a single pass claiming characters greedily.

CONSTRAINTS & BOUNDS

0≤s.length≤1000 \le s.length \le 1000≤s.length≤100, 0≤t.length≤1040 \le t.length \le 10^40≤t.length≤104. Budget: O(len(t))O(len(t))O(len(t)) time, O(1)O(1)O(1) space -- one pass over the longer string, no extra memory beyond two counters.

FAANG PRODUCTION TRAPS & EDGE CASES

Advancing i on every character of t, not only on a match, lets the final check pass even when s is not really a subsequence of t. The follow-up (many strings checked against the same t) changes the cost model: indexing t's letter positions once and binary-searching them per query turns many single-pass scans into one O(n log n) build plus O(m log n) per query, where this card's own approach alone would cost O(q * len(t)) across q queries.

© 2026 Hi👋WebEnterprise. All rights reserved.
Sitemap•llms.txt•