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•Binary Search Boundary
MediumLC 34

Find First and Last Position of Element in Sorted Array (LC 34)

Target Frequency:MetaAmazonGoogleNetflix

You're given an array nums sorted in non-decreasing order and a target value. Find the first and last index at which target occurs.

If target never appears, answer [-1, -1].

Your algorithm must run in O(log n) time.

Worked Examples

Example 1
Input:nums = [5,7,7,8,8,10], target = 8
Output:[3,4]
Explanation: The target 8 appears first at index 3 and last at index 4.
Example 2
Input:nums = [5,7,7,8,8,10], target = 6
Output:[-1,-1]
Explanation: The target 6 does not exist in nums, so [-1, -1] is returned.
Example 3
Input:nums = [], target = 0
Output:[-1,-1]
Explanation: The array is empty, so [-1, -1] is returned.

⚖️Formal Constraints & Bounds

  • 0 <= nums.length <= 105

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

  • nums is a non-decreasing array.

  • -109 <= target <= 109

Deep-Dive & Conceptual Insights

Core Insight

When nums[mid] == target, do not exit. Record the index and continue searching left (hi = mid - 1) for the first occurrence, or right (lo = mid + 1) for the last.

Real-World Scenario & Production Applications

In search engines and financial transaction ledgers, identical timestamps or duplicate transaction IDs frequently occur. Finding the exact starting index of duplicate events is critical for interval scans.

Step-by-Step Execution Trace Table

First occurrence pass (leftward bias):

Step(left, right)midnums[mid]ResultActionAfter
10, 632MatchRecord first = 3, push left → right = 20, 2
20, 212MatchRecord first = 1, push left → right = 00, 0
30, 001Too smallNot a match (1 < 2) → left = 11, 0
41, 0——Emptyleft > right → stopreturns 1

Last occurrence pass (rightward bias, same code with one branch flipped):

Step(left, right)midnums[mid]ResultActionAfter
10, 632MatchRecord last = 3, push right → left = 44, 6
24, 653Too largeNot a match (3 > 2) → right = 44, 4
34, 442MatchRecord last = 4, push right → left = 55, 4
45, 4——Emptyleft > right → stopreturns 4
Code Shape
Archetype Code Shape
Python
1left, right = 0, len(nums) - 1
2bound = -1
3while left <= right:
4 mid = left + (right - left) // 2
5 if nums[mid] == target:
6 bound, right = mid, mid - 1
7 elif nums[mid] < target:
8 left = mid + 1
9 else:
10 right = mid - 1
11return bound

Conceptual Narrative

🧭 Conceptual Foundation & Pattern Intuition

When an array contains duplicate copies of the target value (e.g. [5, 7, 7, 8, 8, 10] with target = 8), standard exact-match binary search fails because it halts on the very first match it stumbles upon. Depending on array length, that initial encounter could be at index 3 or index 4. To find the exact boundary—the first (leftmost) occurrence or last (rightmost) occurrence—we must convert binary search from an equality-seeker into a boundary-seeking predicate recorder.

🏟️ The Analogy: The Quality Control Inspector on a Conveyor Belt

Imagine an assembly line where defective parts are marked with stamp "8". You need to find the exact moment the machine started producing defects (the first "8"). If you sample a part in the middle and it has stamp "8", you do not stop there. You write down that part's serial number on your clipboard as your "best known suspect so far", and then you immediately walk upstream (towards the left) to see if an even earlier part was stamped with "8". You only stop when you've inspected all upstream candidates.

🔑 Why It Works

By replacing return mid with bound = mid followed by an aggressive boundary push (hi = mid - 1 or lo = mid + 1), we turn binary search into a monotonic boundary finder without sacrificing its O(log⁡N)O(\log N)O(logN) efficiency.

  • Early exit on first target match: Returning immediately upon nums[mid] == target finds an arbitrary occurrence, not the first (or last) occurrence in a duplicate run. You must record ans = mid and continue searching left (hi = mid - 1).

  • Separate non-monotonic loops for bounds: Implementing left-bound and right-bound search with different conditional heuristics creates subtle off-by-one bugs. Use a unified binary search helper parameterized by search direction.

  • Target absent returning [0, 0]: If the target does not exist in the array, the function must return [-1, -1]. Ensure the validation check verifies nums[left] == target before returning.

Senior SWE Reasoning Architecture

4-Phase Thought Process Model

Pattern Recognition Signals

The 10-second spot

Sorted array containing duplicate elements + requirement to find the FIRST (leftmost) or LAST (rightmost) occurrence of a target value.

Formulating the Predicate & Invariants

Turning intuition into a boolean rule

Invariant: the leftmost occurrence of target, if it exists, always lies within [left, right]. A match at mid only records a candidate — it never proves leftmost — so the interval keeps narrowing left instead of returning.

Silent Failure Traps & Edge Cases

Where confident candidates still lose points

  • Empty/Missing Verification: Forgetting to verify that boundary_index != -1 before returning.

The 60-Second Interview Pitch

Say this out loud before you type a single line

"Since the array contains duplicates, finding a match at nums[mid] is not sufficient to prove it is the first occurrence. I record mid as a potential answer and continue searching strictly to the left by setting right = mid - 1. This guarantees we isolate the leftmost occurrence in O(log N) time and O(1) space."

Big-O Invariant Derivation

Complexity & Mathematical Proof

TIME COMPLEXITY

O(log N)

Look at the two sequential binary search helper functions (findFirst and findLast): Each executes an independent while loop while lo <= hi:. Each loop halves the search space from N down to 1 in at most ceil(log2 N) iterations doing O(1) work per step. Summing both passes: O(log N) + O(log N) = 2 · O(log N) = O(log N) total time.

SPACE COMPLEXITY

O(1) Auxiliary

Look at memory allocation: Both binary search passes run iteratively without recursive call frames (O(1) stack). We store only scalar boundary registers. Output is a 2-element list [first, last]. Auxiliary space is strictly O(1) in-place.

Formal Recurrence Relation

T(N)=2⋅O(log⁡N)=O(log⁡N)T(N) = 2 · O(\log N) = O(\log N)T(N)=2⋅O(logN)=O(logN)

Derivation Progression

First Occurrence Pass

Pass 1 (findFirst): O(log N)

First while loop pushes left on matches (hi = mid - 1) to find the earliest target index in O(log N) steps.

Last Occurrence Pass

Pass 2 (findLast): O(log N)

Second while loop pushes right on matches (lo = mid + 1) to find the latest target index in O(log N) steps.

Total Asymptotic Sum

O(log N) + O(log N) = O(log N)

Two sequential logarithmic passes combine to strictly O(log N) runtime.

Variable Definitions

NNN

Total number of elements in the sorted array

Memory Architecture & Bounds

🟣 Call Stack

O(1) Iterative passes with zero recursion frames

🔵 Auxiliary Heap

O(1) Scalar boundary registers only

🟢 Output Space

O(1) Returns 2-element index pair [first, last]

Boundary Best / Worst Cases

Best Case

O(log⁡N)O(\log N)O(logN) — Both binary search runs execute to logarithmic exhaustion.

Average Case

O(log⁡N)O(\log N)O(logN) — Consistent across all element distributions.

Worst Case

O(log⁡N)O(\log N)O(logN) — Target occupies entire array; binary search still halves each step.

Recurrence Tree Topology

Recurrence Tree Topology
Synthesizing vector architecture diagram...
Staff+ Engineering Perspective

Senior SWE Deconstruction & Hardware Caveats

ARCHITECTURAL SIGNALS & INTERVIEW TRIGGERS

The defining signal is "sorted in non-decreasing order" coupled with the requirement to find both the "starting and ending position of a given target value." The presence of non-distinct elements (duplicates) means that exact-match binary search fails: landing on nums[mid] == target gives an arbitrary index inside a cluster of duplicates. To isolate both edges of the cluster, we must decouple the problem into two distinct binary searches with directional tie-breaking bias: one biased leftward (first occurrence) and one biased rightward (last occurrence).

CONSTRAINTS & BOUNDS

With N≤105N \le 10^5N≤105, an O(N)O(N)O(N) scan expanding outward from a matched midpoint will degrade to O(N)O(N)O(N) worst-case time on arrays like nums = [8, 8, ..., 8], triggering Time Limit Exceeded. Both searches must run in strictly logarithmic time. For both passes, the search bounds are lo = 0 and hi = len(nums) - 1. If the target is not found in the first pass, the second pass can be skipped entirely, immediately returning [-1, -1].

FAANG PRODUCTION TRAPS & EDGE CASES

The most frequent trap is writing a single binary search to find any match, followed by a linear while-loop to expand left and right. That naive hybrid collapses to O(N)O(N)O(N) on uniform arrays. Edge cases include empty arrays (nums = []), target completely absent (smaller than nums[0] or greater than nums[-1]), and arrays where target appears as a singleton (first_pos == last_pos).

Theory Context•Binary Search Boundary
MediumLC 34

Find First and Last Position of Element in Sorted Array (LC 34)

Target Frequency:MetaAmazonGoogleNetflix

You're given an array nums sorted in non-decreasing order and a target value. Find the first and last index at which target occurs.

If target never appears, answer [-1, -1].

Your algorithm must run in O(log n) time.

Worked Examples

Example 1
Input:nums = [5,7,7,8,8,10], target = 8
Output:[3,4]
Explanation: The target 8 appears first at index 3 and last at index 4.
Example 2
Input:nums = [5,7,7,8,8,10], target = 6
Output:[-1,-1]
Explanation: The target 6 does not exist in nums, so [-1, -1] is returned.
Example 3
Input:nums = [], target = 0
Output:[-1,-1]
Explanation: The array is empty, so [-1, -1] is returned.

⚖️Formal Constraints & Bounds

  • 0 <= nums.length <= 105

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

  • nums is a non-decreasing array.

  • -109 <= target <= 109

Deep-Dive & Conceptual Insights

Core Insight

When nums[mid] == target, do not exit. Record the index and continue searching left (hi = mid - 1) for the first occurrence, or right (lo = mid + 1) for the last.

Real-World Scenario & Production Applications

In search engines and financial transaction ledgers, identical timestamps or duplicate transaction IDs frequently occur. Finding the exact starting index of duplicate events is critical for interval scans.

Step-by-Step Execution Trace Table

First occurrence pass (leftward bias):

Step(left, right)midnums[mid]ResultActionAfter
10, 632MatchRecord first = 3, push left → right = 20, 2
20, 212MatchRecord first = 1, push left → right = 00, 0
30, 001Too smallNot a match (1 < 2) → left = 11, 0
41, 0——Emptyleft > right → stopreturns 1

Last occurrence pass (rightward bias, same code with one branch flipped):

Step(left, right)midnums[mid]ResultActionAfter
10, 632MatchRecord last = 3, push right → left = 44, 6
24, 653Too largeNot a match (3 > 2) → right = 44, 4
34, 442MatchRecord last = 4, push right → left = 55, 4
45, 4——Emptyleft > right → stopreturns 4
Code Shape
Archetype Code Shape
Python
1left, right = 0, len(nums) - 1
2bound = -1
3while left <= right:
4 mid = left + (right - left) // 2
5 if nums[mid] == target:
6 bound, right = mid, mid - 1
7 elif nums[mid] < target:
8 left = mid + 1
9 else:
10 right = mid - 1
11return bound

Conceptual Narrative

🧭 Conceptual Foundation & Pattern Intuition

When an array contains duplicate copies of the target value (e.g. [5, 7, 7, 8, 8, 10] with target = 8), standard exact-match binary search fails because it halts on the very first match it stumbles upon. Depending on array length, that initial encounter could be at index 3 or index 4. To find the exact boundary—the first (leftmost) occurrence or last (rightmost) occurrence—we must convert binary search from an equality-seeker into a boundary-seeking predicate recorder.

🏟️ The Analogy: The Quality Control Inspector on a Conveyor Belt

Imagine an assembly line where defective parts are marked with stamp "8". You need to find the exact moment the machine started producing defects (the first "8"). If you sample a part in the middle and it has stamp "8", you do not stop there. You write down that part's serial number on your clipboard as your "best known suspect so far", and then you immediately walk upstream (towards the left) to see if an even earlier part was stamped with "8". You only stop when you've inspected all upstream candidates.

🔑 Why It Works

By replacing return mid with bound = mid followed by an aggressive boundary push (hi = mid - 1 or lo = mid + 1), we turn binary search into a monotonic boundary finder without sacrificing its O(log⁡N)O(\log N)O(logN) efficiency.

  • Early exit on first target match: Returning immediately upon nums[mid] == target finds an arbitrary occurrence, not the first (or last) occurrence in a duplicate run. You must record ans = mid and continue searching left (hi = mid - 1).

  • Separate non-monotonic loops for bounds: Implementing left-bound and right-bound search with different conditional heuristics creates subtle off-by-one bugs. Use a unified binary search helper parameterized by search direction.

  • Target absent returning [0, 0]: If the target does not exist in the array, the function must return [-1, -1]. Ensure the validation check verifies nums[left] == target before returning.

Senior SWE Reasoning Architecture

4-Phase Thought Process Model

Pattern Recognition Signals

The 10-second spot

Sorted array containing duplicate elements + requirement to find the FIRST (leftmost) or LAST (rightmost) occurrence of a target value.

Formulating the Predicate & Invariants

Turning intuition into a boolean rule

Invariant: the leftmost occurrence of target, if it exists, always lies within [left, right]. A match at mid only records a candidate — it never proves leftmost — so the interval keeps narrowing left instead of returning.

Silent Failure Traps & Edge Cases

Where confident candidates still lose points

  • Empty/Missing Verification: Forgetting to verify that boundary_index != -1 before returning.

The 60-Second Interview Pitch

Say this out loud before you type a single line

"Since the array contains duplicates, finding a match at nums[mid] is not sufficient to prove it is the first occurrence. I record mid as a potential answer and continue searching strictly to the left by setting right = mid - 1. This guarantees we isolate the leftmost occurrence in O(log N) time and O(1) space."

Big-O Invariant Derivation

Complexity & Mathematical Proof

TIME COMPLEXITY

O(log N)

Look at the two sequential binary search helper functions (findFirst and findLast): Each executes an independent while loop while lo <= hi:. Each loop halves the search space from N down to 1 in at most ceil(log2 N) iterations doing O(1) work per step. Summing both passes: O(log N) + O(log N) = 2 · O(log N) = O(log N) total time.

SPACE COMPLEXITY

O(1) Auxiliary

Look at memory allocation: Both binary search passes run iteratively without recursive call frames (O(1) stack). We store only scalar boundary registers. Output is a 2-element list [first, last]. Auxiliary space is strictly O(1) in-place.

Formal Recurrence Relation

T(N)=2⋅O(log⁡N)=O(log⁡N)T(N) = 2 · O(\log N) = O(\log N)T(N)=2⋅O(logN)=O(logN)

Derivation Progression

First Occurrence Pass

Pass 1 (findFirst): O(log N)

First while loop pushes left on matches (hi = mid - 1) to find the earliest target index in O(log N) steps.

Last Occurrence Pass

Pass 2 (findLast): O(log N)

Second while loop pushes right on matches (lo = mid + 1) to find the latest target index in O(log N) steps.

Total Asymptotic Sum

O(log N) + O(log N) = O(log N)

Two sequential logarithmic passes combine to strictly O(log N) runtime.

Variable Definitions

NNN

Total number of elements in the sorted array

Memory Architecture & Bounds

🟣 Call Stack

O(1) Iterative passes with zero recursion frames

🔵 Auxiliary Heap

O(1) Scalar boundary registers only

🟢 Output Space

O(1) Returns 2-element index pair [first, last]

Boundary Best / Worst Cases

Best Case

O(log⁡N)O(\log N)O(logN) — Both binary search runs execute to logarithmic exhaustion.

Average Case

O(log⁡N)O(\log N)O(logN) — Consistent across all element distributions.

Worst Case

O(log⁡N)O(\log N)O(logN) — Target occupies entire array; binary search still halves each step.

Recurrence Tree Topology

Recurrence Tree Topology
Synthesizing vector architecture diagram...
Staff+ Engineering Perspective

Senior SWE Deconstruction & Hardware Caveats

ARCHITECTURAL SIGNALS & INTERVIEW TRIGGERS

The defining signal is "sorted in non-decreasing order" coupled with the requirement to find both the "starting and ending position of a given target value." The presence of non-distinct elements (duplicates) means that exact-match binary search fails: landing on nums[mid] == target gives an arbitrary index inside a cluster of duplicates. To isolate both edges of the cluster, we must decouple the problem into two distinct binary searches with directional tie-breaking bias: one biased leftward (first occurrence) and one biased rightward (last occurrence).

CONSTRAINTS & BOUNDS

With N≤105N \le 10^5N≤105, an O(N)O(N)O(N) scan expanding outward from a matched midpoint will degrade to O(N)O(N)O(N) worst-case time on arrays like nums = [8, 8, ..., 8], triggering Time Limit Exceeded. Both searches must run in strictly logarithmic time. For both passes, the search bounds are lo = 0 and hi = len(nums) - 1. If the target is not found in the first pass, the second pass can be skipped entirely, immediately returning [-1, -1].

FAANG PRODUCTION TRAPS & EDGE CASES

The most frequent trap is writing a single binary search to find any match, followed by a linear while-loop to expand left and right. That naive hybrid collapses to O(N)O(N)O(N) on uniform arrays. Edge cases include empty arrays (nums = []), target completely absent (smaller than nums[0] or greater than nums[-1]), and arrays where target appears as a singleton (first_pos == last_pos).

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