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
MediumLC 80

Remove Duplicates from Sorted Array II (LeetCode 80)

Target Frequency:MetaGoogleAmazon

You're given an already-sorted (smallest to largest) integer array nums. Trim it in-place so no value shows up more than twice, while keeping the surviving values in their original relative order.

Some languages can't resize an array in place, so instead pack the surviving values into the front of nums. Concretely: if k values remain after the trim, the first k slots of nums must hold them — whatever sits past that point is ignored.

Return that count k once the first k slots of nums hold the final result.

You must do this without allocating another array — only O(1)O(1)O(1) extra memory, modifying nums directly.

Custom Judge:

We compare the k you return with the length of the expected trimmed array, then check that each of the first k slots of nums holds the expected value for that position. Anything after slot k - 1 is ignored.

Worked Examples

Example 1
Input:nums = [1,1,1,2,2,3]
Output:5, nums = [1,1,2,2,3,_]
Explanation: k comes back as 5, with the first five slots of nums holding 1, 1, 2, 2, and 3 in order. Whatever is left past index k-1 (shown as an underscore) is never checked.
Example 2
Input:nums = [0,0,1,1,1,1,2,3,3]
Output:7, nums = [0,0,1,1,2,3,3,_,_]
Explanation: k comes back as 7, with the first seven slots of nums holding 0, 0, 1, 1, 2, 3, and 3 in order. Whatever is left past index k-1 (shown as underscores) is never checked.

⚖️Formal Constraints & Bounds

  • 1 <= nums.length <= 3 * 104

  • -104 <= nums[i] <= 104

  • nums is sorted in non-decreasing order.

Deep-Dive & Conceptual Insights

Core Insight

Comparing candidate elements against nums[writer - 2] directly enforces the at-most-2 invariant without needing auxiliary counters.

Real-World Scenario & Production Applications

Memory compaction with bounded frequency quotas, rate-limiting transaction buffers, and bounded-run compression.

Subproblems & Recurrence Decomposition3 Phases

🧩Subproblem 1: Two-Behind Write-Read Pointer Setup

slow tracks the next write position; the first two elements are always kept unconditionally since any value is allowed to appear at least twice.

Mathematical Recurrence / Code Invariant
slow = 2  # first 2 elements are always kept

Step-by-Step Execution Trace Table

Stepreadernums[reader]nums[writer - 2]ActionMutated Array Prefixwriter
init———Keep first 2 elements automatically[1, 1, ...]2
12113rd duplicate (1 == 1) →\rightarrow→ skip[1, 1, ...]2
2321Novel element (2 != 1) →\rightarrow→ nums[2] = 2, writer++[1, 1, 2, ...]3
34212nd copy of 2 (2 != 1) →\rightarrow→ nums[3] = 2, writer++[1, 1, 2, 2, ...]4
4532Novel element (3 != 2) →\rightarrow→ nums[4] = 3, writer++[1, 1, 2, 2, 3]5
Code Shape
Archetype Code Shape
Python
1if len(nums) <= 2:
2 return len(nums)
3writer = 2
4for reader in range(2, len(nums)):
5 if nums[reader] != nums[writer - 2]:
6 nums[writer] = nums[reader]
7 writer += 1
8return writer

Conceptual Narrative

🧭 Conceptual Foundation & Pattern Intuition

When deduplication rules relax from "at most 1" to "at most kkk" duplicates (here k=2k=2k=2), many reach for counter dictionaries or state variables. The Reader-Writer pattern solves this universally with zero additional variables.

🏆 The Core Invariant: The Kept-Prefix Boundary

The kept prefix nums[0..writer-1] is your certified result so far. If you allow at most kkk duplicates, the earliest copy of the current number you could have kept is at writer - k. Because the array is sorted, any element equal to nums[writer - k] has already reached its quota of kkk copies in the output prefix.

🏷️ The Analogy: A VIP Room with a Strict 2-Guest Limit

Imagine a VIP lounge where each guest type can bring at most 2 friends. The bouncer (writer) admits the first 2 guests unconditionally (writer = 2). For every subsequent person in line (reader), the bouncer doesn't need a clipboard. Because guests arrive grouped by type (sorted array), the bouncer simply looks at the guest admitted two slots ago (writer - 2). If the current person matches, the 2-person quota is full! If they differ, admission is granted: write nums[writer] = nums[reader] and advance writer.

🔑 Why It Works

If nums[reader] == nums[writer - 2], then since the array is sorted, nums[writer - 1] is also equal to nums[reader]. Adding nums[reader] would create a 3rd duplicate! Skipping it preserves the at-most-2 invariant automatically.

  • Comparing against reader - 2 instead of writer - 2: When allowing at most k=2k=2k=2 duplicates, you must compare the incoming candidate nums[reader] against the finalized element committed two slots ago (nums[writer - 2]). Comparing against reader - 2 gets fooled by runs of 3+ duplicates.

  • Premature loop start index: The first 2 elements (indices 0 and 1) are always valid regardless of values. The loop must initialize writer = 2 and scan reader from index 2.

  • Returning writer + 1 instead of writer: Because writer is zero-indexed and points to the next available slot, its value directly equals the number of preserved elements.

Senior SWE Reasoning Architecture

4-Phase Thought Process Model

Pattern Recognition Signals

The 10-second spot

Sorted array + in-place modification + allow up to k duplicates + O(1) memory requirement.

Formulating the Predicate & Invariants

Turning intuition into a boolean rule

Invariant: nums[0..writer-1] contains the sorted elements with at most 2 occurrences each. If nums[reader] != nums[writer-2], nums[writer] = nums[reader] and writer increments.

Silent Failure Traps & Edge Cases

Where confident candidates still lose points

  • Using counter variables and reset flags instead of looking back into the trusted kept array.

  • Boundary check failure when len(nums) <= 2: guard if len(nums) <= 2: return len(nums).

The 60-Second Interview Pitch

Say this out loud before you type a single line

"I initialize writer = 2 since the first two elements are always valid. The reader scans from index 2; whenever nums[reader] differs from nums[writer-2], we have not yet exceeded our quota of two duplicates, so I write at nums[writer] and increment writer. Runs in O(N) time and O(1) space."

Big-O Invariant Derivation

Complexity & Mathematical Proof

TIME COMPLEXITY

O(N)

Look at the execution steps: Reader pointer scans each element exactly once from index 2 to N-1; writer pointer writes at most N times in-place. Total operations are strictly linear in N.

SPACE COMPLEXITY

O(1) Auxiliary

Look at memory allocations: Call stack uses O(1) Iterative. Only two scalar integer pointers (reader, writer) are stored in constant memory.

Formal Recurrence Relation

T(N) = O(N)

Derivation Progression

Direct Pass Scan

for reader in range(2, N)

Reader pointer visits elements starting from index 2 to end exactly once.

Bounded Write Verification

if nums[reader] != nums[writer - 2]: nums[writer] = nums[reader], writer++

Writer advances strictly when candidate does not exceed the quota of 2 duplicates.

Linear Time In-Place

O(N) total steps

Array is mutated in-place with zero heap allocations.

Variable Definitions

NNN

Total number of elements in the sorted array

Memory Architecture & Bounds

🟣 Call Stack

O(1) Iterative

🔵 Auxiliary Heap

O(1) Zero heap allocations

🟢 Output Space

O(1) Returns integer count

Boundary Best / Worst Cases

Best Case

O(N)O(N)O(N)

Average Case

O(N)O(N)O(N)

Worst Case

O(N)O(N)O(N)

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: "at most twice", "in-place with O(1) extra memory". Generalized kkk-duplicate compaction problem (k=2k=2k=2). Instead of comparing candidate nums[read] with immediately preceding element, compare it against the element written kkk steps ago (nums[write - k]).

CONSTRAINTS & BOUNDS

1≤N≤3×1041 \le N \le 3 \times 10^41≤N≤3×104. Requires O(N)O(N)O(N) time and O(1)O(1)O(1) space. Boundary choice: if N≤2N \le 2N≤2, every element is valid; write pointer starts at index 2.

FAANG PRODUCTION TRAPS & EDGE CASES

Comparing against read - 2 checks the raw unsifted input array, which allows duplicate runs of length >2> 2>2 if writes lag behind reads. Must always compare against the compacted output buffer nums[write - 2].

Theory Context•Two Pointers & Sliding Window
MediumLC 80

Remove Duplicates from Sorted Array II (LeetCode 80)

Target Frequency:MetaGoogleAmazon

You're given an already-sorted (smallest to largest) integer array nums. Trim it in-place so no value shows up more than twice, while keeping the surviving values in their original relative order.

Some languages can't resize an array in place, so instead pack the surviving values into the front of nums. Concretely: if k values remain after the trim, the first k slots of nums must hold them — whatever sits past that point is ignored.

Return that count k once the first k slots of nums hold the final result.

You must do this without allocating another array — only O(1)O(1)O(1) extra memory, modifying nums directly.

Custom Judge:

We compare the k you return with the length of the expected trimmed array, then check that each of the first k slots of nums holds the expected value for that position. Anything after slot k - 1 is ignored.

Worked Examples

Example 1
Input:nums = [1,1,1,2,2,3]
Output:5, nums = [1,1,2,2,3,_]
Explanation: k comes back as 5, with the first five slots of nums holding 1, 1, 2, 2, and 3 in order. Whatever is left past index k-1 (shown as an underscore) is never checked.
Example 2
Input:nums = [0,0,1,1,1,1,2,3,3]
Output:7, nums = [0,0,1,1,2,3,3,_,_]
Explanation: k comes back as 7, with the first seven slots of nums holding 0, 0, 1, 1, 2, 3, and 3 in order. Whatever is left past index k-1 (shown as underscores) is never checked.

⚖️Formal Constraints & Bounds

  • 1 <= nums.length <= 3 * 104

  • -104 <= nums[i] <= 104

  • nums is sorted in non-decreasing order.

Deep-Dive & Conceptual Insights

Core Insight

Comparing candidate elements against nums[writer - 2] directly enforces the at-most-2 invariant without needing auxiliary counters.

Real-World Scenario & Production Applications

Memory compaction with bounded frequency quotas, rate-limiting transaction buffers, and bounded-run compression.

Subproblems & Recurrence Decomposition3 Phases

🧩Subproblem 1: Two-Behind Write-Read Pointer Setup

slow tracks the next write position; the first two elements are always kept unconditionally since any value is allowed to appear at least twice.

Mathematical Recurrence / Code Invariant
slow = 2  # first 2 elements are always kept

Step-by-Step Execution Trace Table

Stepreadernums[reader]nums[writer - 2]ActionMutated Array Prefixwriter
init———Keep first 2 elements automatically[1, 1, ...]2
12113rd duplicate (1 == 1) →\rightarrow→ skip[1, 1, ...]2
2321Novel element (2 != 1) →\rightarrow→ nums[2] = 2, writer++[1, 1, 2, ...]3
34212nd copy of 2 (2 != 1) →\rightarrow→ nums[3] = 2, writer++[1, 1, 2, 2, ...]4
4532Novel element (3 != 2) →\rightarrow→ nums[4] = 3, writer++[1, 1, 2, 2, 3]5
Code Shape
Archetype Code Shape
Python
1if len(nums) <= 2:
2 return len(nums)
3writer = 2
4for reader in range(2, len(nums)):
5 if nums[reader] != nums[writer - 2]:
6 nums[writer] = nums[reader]
7 writer += 1
8return writer

Conceptual Narrative

🧭 Conceptual Foundation & Pattern Intuition

When deduplication rules relax from "at most 1" to "at most kkk" duplicates (here k=2k=2k=2), many reach for counter dictionaries or state variables. The Reader-Writer pattern solves this universally with zero additional variables.

🏆 The Core Invariant: The Kept-Prefix Boundary

The kept prefix nums[0..writer-1] is your certified result so far. If you allow at most kkk duplicates, the earliest copy of the current number you could have kept is at writer - k. Because the array is sorted, any element equal to nums[writer - k] has already reached its quota of kkk copies in the output prefix.

🏷️ The Analogy: A VIP Room with a Strict 2-Guest Limit

Imagine a VIP lounge where each guest type can bring at most 2 friends. The bouncer (writer) admits the first 2 guests unconditionally (writer = 2). For every subsequent person in line (reader), the bouncer doesn't need a clipboard. Because guests arrive grouped by type (sorted array), the bouncer simply looks at the guest admitted two slots ago (writer - 2). If the current person matches, the 2-person quota is full! If they differ, admission is granted: write nums[writer] = nums[reader] and advance writer.

🔑 Why It Works

If nums[reader] == nums[writer - 2], then since the array is sorted, nums[writer - 1] is also equal to nums[reader]. Adding nums[reader] would create a 3rd duplicate! Skipping it preserves the at-most-2 invariant automatically.

  • Comparing against reader - 2 instead of writer - 2: When allowing at most k=2k=2k=2 duplicates, you must compare the incoming candidate nums[reader] against the finalized element committed two slots ago (nums[writer - 2]). Comparing against reader - 2 gets fooled by runs of 3+ duplicates.

  • Premature loop start index: The first 2 elements (indices 0 and 1) are always valid regardless of values. The loop must initialize writer = 2 and scan reader from index 2.

  • Returning writer + 1 instead of writer: Because writer is zero-indexed and points to the next available slot, its value directly equals the number of preserved elements.

Senior SWE Reasoning Architecture

4-Phase Thought Process Model

Pattern Recognition Signals

The 10-second spot

Sorted array + in-place modification + allow up to k duplicates + O(1) memory requirement.

Formulating the Predicate & Invariants

Turning intuition into a boolean rule

Invariant: nums[0..writer-1] contains the sorted elements with at most 2 occurrences each. If nums[reader] != nums[writer-2], nums[writer] = nums[reader] and writer increments.

Silent Failure Traps & Edge Cases

Where confident candidates still lose points

  • Using counter variables and reset flags instead of looking back into the trusted kept array.

  • Boundary check failure when len(nums) <= 2: guard if len(nums) <= 2: return len(nums).

The 60-Second Interview Pitch

Say this out loud before you type a single line

"I initialize writer = 2 since the first two elements are always valid. The reader scans from index 2; whenever nums[reader] differs from nums[writer-2], we have not yet exceeded our quota of two duplicates, so I write at nums[writer] and increment writer. Runs in O(N) time and O(1) space."

Big-O Invariant Derivation

Complexity & Mathematical Proof

TIME COMPLEXITY

O(N)

Look at the execution steps: Reader pointer scans each element exactly once from index 2 to N-1; writer pointer writes at most N times in-place. Total operations are strictly linear in N.

SPACE COMPLEXITY

O(1) Auxiliary

Look at memory allocations: Call stack uses O(1) Iterative. Only two scalar integer pointers (reader, writer) are stored in constant memory.

Formal Recurrence Relation

T(N) = O(N)

Derivation Progression

Direct Pass Scan

for reader in range(2, N)

Reader pointer visits elements starting from index 2 to end exactly once.

Bounded Write Verification

if nums[reader] != nums[writer - 2]: nums[writer] = nums[reader], writer++

Writer advances strictly when candidate does not exceed the quota of 2 duplicates.

Linear Time In-Place

O(N) total steps

Array is mutated in-place with zero heap allocations.

Variable Definitions

NNN

Total number of elements in the sorted array

Memory Architecture & Bounds

🟣 Call Stack

O(1) Iterative

🔵 Auxiliary Heap

O(1) Zero heap allocations

🟢 Output Space

O(1) Returns integer count

Boundary Best / Worst Cases

Best Case

O(N)O(N)O(N)

Average Case

O(N)O(N)O(N)

Worst Case

O(N)O(N)O(N)

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: "at most twice", "in-place with O(1) extra memory". Generalized kkk-duplicate compaction problem (k=2k=2k=2). Instead of comparing candidate nums[read] with immediately preceding element, compare it against the element written kkk steps ago (nums[write - k]).

CONSTRAINTS & BOUNDS

1≤N≤3×1041 \le N \le 3 \times 10^41≤N≤3×104. Requires O(N)O(N)O(N) time and O(1)O(1)O(1) space. Boundary choice: if N≤2N \le 2N≤2, every element is valid; write pointer starts at index 2.

FAANG PRODUCTION TRAPS & EDGE CASES

Comparing against read - 2 checks the raw unsifted input array, which allows duplicate runs of length >2> 2>2 if writes lag behind reads. Must always compare against the compacted output buffer nums[write - 2].

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