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 852

Peak Index in a Mountain Array (LC 852)

Target Frequency:AmazonGoogleMeta

You're given a mountain array arr of length n: its values climb up to one peak and then descend.

Return the index of that peak.

Solve it in O(log n) time.

Worked Examples

Example 1
Input:arr = [0,1,0]
Output:1
Explanation: The peak element is 1 at index 1.
Example 2
Input:arr = [0,2,1,0]
Output:1
Explanation: The peak element is 2 at index 1.
Example 3
Input:arr = [0,10,5,2]
Output:1
Explanation: The peak element is 10 at index 1.

⚖️Formal Constraints & Bounds

  • 3 <= arr.length <= 105

  • 0 <= arr[i] <= 106

  • arr is guaranteed to be a mountain array.

Deep-Dive & Conceptual Insights

Core Insight

Compare arr[mid] with arr[mid + 1]. If the values fall after mid, a peak is at mid or to its left (hi = mid). If they rise, a peak is to its right (lo = mid + 1). Even when the values are not sorted, this one comparison removes half of the candidates.

Real-World Scenario & Production Applications

Terrain navigation sensor processing, signal processing peak detection, and CPU frequency throttling curves.

Subproblems & Recurrence Decomposition3 Phases

🧩Subproblem 1: The Check And The Range

Ask each index one yes-or-no question: do the values fall after i? That is arr[i] > arr[i + 1]. The check reads the next value, so the candidates are 0 to n - 2, and the range is [lo, hi) = [0, n - 1).

Mathematical Recurrence / Code Invariant
# Check: do the values fall after i?
def is_falling(i):
    return arr[i] > arr[i + 1]
lo, hi = 0, n - 1

Step-by-Step Execution Trace Table

StepRange [lo, hi)midarr[mid] > arr[mid + 1]?DecisionNew range [lo, hi)
1[0, 6)310 > 8 → TrueThe values fall after 3, so a peak is at 3 or to its left: hi = mid[0, 3)
2[0, 3)12 > 5 → FalseThe values rise after 1, so a peak is to its right: lo = mid + 1[2, 3)
3[2, 3)25 > 10 → FalseThe values rise after 2, so a peak is to its right: lo = mid + 1[3, 3)
4[3, 3)The range is empty. Lower Bound returns 3, and arr[3] = 10 is the peak.

The trace for arr = [0, 2, 5, 10, 8, 4, 1], step by step:

  • The candidates are the indices 0 to 5, because the check reads the next value. So lo = 0 and hi = 6.
  • Step 1 checks mid = 3: arr[3] = 10 and arr[4] = 8. The check is True, so a peak is at index 3 or to its left. We keep index 3 with hi = mid.
  • Step 2 checks mid = 1: arr[1] = 2 and arr[2] = 5. The check is False, so a peak is to the right. We skip index 1 with lo = mid + 1.
  • Step 3 checks mid = 2: arr[2] = 5 and arr[3] = 10. The check is False, so lo = mid + 1 = 3.
  • Step 4: lo is equal to hi, so the range is empty. Lower Bound returns 3.
Code Shape
Archetype Code Shape
Python
1def is_falling(i: int) -> bool:
2 return arr[i] > arr[i + 1]
3lo = 0
4hi = n - 1
5return binary_search_lower_bound(lo, hi, is_falling)

Conceptual Narrative

🧭 Conceptual Foundation & Pattern Intuition

Extrema Search compares a value with the value next to it, not with a target. The check asks one question about the slope: do the values fall after this index? If they fall, a peak is at this index or to its left. If they rise, a peak is to its right.

⛰️ The Analogy: Walking Uphill In The Dark

Imagine a path over a hill, and you cannot see the top. At any point, you can feel if the next step goes up or down. If the next step goes up, the top is ahead of you. If the next step goes down, you are on the top or you have passed it. You never need to know your height. You only need the direction of the next step.

🔑 Why It Works

The loop keeps one fact: a peak is always at an index from lo to hi. Lower Bound uses the check arr[i] > arr[i + 1]. When every check is False, the values rise to the end, so the last index is a peak. On a mountain, the check is False and then True, so the first True is the top. On a list with several peaks, the check is not False and then True, and the search still returns one peak, not the highest.

  • Setting hi = n while the check reads arr[i + 1]

  • Using the check when two neighbouring values can be equal

  • Returning the value instead of the index

  • In the grid, comparing a cell with its left and right neighbours at the same time

  • In the grid, comparing the first cell of the column instead of its largest cell

Senior SWE Reasoning Architecture

4-Phase Thought Process Model

Pattern Recognition Signals

The 10-second spot

"Its values climb up to one peak and then descend. Return the index of that peak. Solve it in O(log n) time.": a rise-then-fall shape and a logarithmic budget point to Extrema Search.

Formulating the Predicate & Invariants

Turning intuition into a boolean rule

Invariant: a peak is always at an index from lo to hi. The check arr[i] > arr[i + 1] asks if the values fall after i. On a mountain, it is False and then True, so Lower Bound finds the first True, the top. On a list with several peaks, it is not False and then True, and the invariant still holds.

Silent Failure Traps & Edge Cases

Where confident candidates still lose points

  • Setting hi = n while the check reads arr[i + 1]: the last candidate reads past the end, and Python raises an IndexError (arr = [1, 2, 3]). The candidates are 0 to n - 2, so hi = n - 1.

  • Expecting the highest peak: with several peaks the search returns one of them, and arr = [3, 1, 2] returns index 2, not index 0.

The 60-Second Interview Pitch

Say this out loud before you type a single line

"This is Extrema Search. I run Lower Bound with the check arr[i] > arr[i + 1], which asks if the values fall after i. If they fall, a peak is at i or to its left, so Lower Bound keeps mid. If they rise, a peak is to its right, so Lower Bound skips mid. The check reads the next value, so the candidates stop at n - 2, and I call binary_search_lower_bound(0, n - 1, is_falling). When no candidate is True, the values rise to the end, and the last index is the peak. A peak is always between lo and hi, so the search never loses it. The trap is expecting the highest peak: with several peaks, I return one of them. Each pass halves the range, so it is O(log n) time and O(1) space."

Big-O Invariant Derivation

Complexity & Mathematical Proof

TIME COMPLEXITY

O(log N)

Look at the loop in Lower Bound: while lo < hi:. Each pass does one comparison, arr[mid] > arr[mid + 1], and keeps either [lo, mid) or [mid + 1, hi), which is at most half of the range. From N indices the loop runs at most ⌊log2 N⌋ + 1 times with O(1) work each: O(log N) time.

SPACE COMPLEXITY

O(1)

Look at the memory used: the loop is iterative, so the call stack holds one frame. We store only the integers lo, hi and mid. Auxiliary space is O(1).

Formal Recurrence Relation

T(N)=T(N/2)+O(1)⟹O(log⁡N)T(N) = T(N/2) + O(1) ⟹ O(\log N)T(N)=T(N/2)+O(1)⟹O(logN)

Derivation Progression

Slope Detection

delta = arr[mid+1] - arr[mid]

If delta > 0, the values rise after mid, so a peak is to its right. Otherwise a peak is at mid or to its left.

Interval Elimination

lo = mid + 1 or hi = mid

A peak is always at an index from lo to hi, so removing the other part never loses it.

Convergence

lo == hi ⟹ O(log N)

Converges on a peak in at most floor(log2 N) + 1 iterations.

Variable Definitions

NNN

Total number of elements in the mountain array

Memory Architecture & Bounds

🟣 Call Stack

O(1) Iterative

🔵 Auxiliary Heap

O(1) Scalar registers

🟢 Output Space

O(1) Peak index integer

Boundary Best / Worst Cases

Best Case

O(log⁡N)O(\log N)O(logN) — Fixed binary search convergence.

Average Case

O(log⁡N)O(\log N)O(logN).

Worst Case

O(log⁡N)O(\log N)O(logN) — Every pass halves the range.

Recurrence Tree Topology

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

Senior SWE Deconstruction & Hardware Caveats

ARCHITECTURAL SIGNALS & INTERVIEW TRIGGERS

The statement describes a "mountain array" whose values "climb up to one peak and then descend", and asks for the peak's index "in O(log n) time". This is Extrema Search: nothing is compared with a target. The check arr[i] > arr[i + 1] asks if the values fall after i, and Lower Bound finds the first index where they do.

CONSTRAINTS & BOUNDS

The array length is 3≤N≤1053 \le N \le 10^53≤N≤105, with elements up to 10610^6106. The mountain property guarantees that the peak never resides at index 000 or index N−1N - 1N−1. The check reads arr[i + 1], so the candidates are 0 to n - 2, and the search range is lo = 0 and hi = n - 1.

FAANG PRODUCTION TRAPS & EDGE CASES

The card's trap is expecting the highest peak: with several peaks, the search returns one of them. A second trap is setting hi = n, which makes the last candidate read arr[n]. At scale there is one more: the data. With plateaus or equal neighbours the slope check is blind, so either confirm that neighbours differ or fall back to a linear scan. With noisy values, one comparison can point the wrong way, so compare smoothed values or wider gaps instead of single neighbours.

Theory Context•Binary Search Boundary
MediumLC 852

Peak Index in a Mountain Array (LC 852)

Target Frequency:AmazonGoogleMeta

You're given a mountain array arr of length n: its values climb up to one peak and then descend.

Return the index of that peak.

Solve it in O(log n) time.

Worked Examples

Example 1
Input:arr = [0,1,0]
Output:1
Explanation: The peak element is 1 at index 1.
Example 2
Input:arr = [0,2,1,0]
Output:1
Explanation: The peak element is 2 at index 1.
Example 3
Input:arr = [0,10,5,2]
Output:1
Explanation: The peak element is 10 at index 1.

⚖️Formal Constraints & Bounds

  • 3 <= arr.length <= 105

  • 0 <= arr[i] <= 106

  • arr is guaranteed to be a mountain array.

Deep-Dive & Conceptual Insights

Core Insight

Compare arr[mid] with arr[mid + 1]. If the values fall after mid, a peak is at mid or to its left (hi = mid). If they rise, a peak is to its right (lo = mid + 1). Even when the values are not sorted, this one comparison removes half of the candidates.

Real-World Scenario & Production Applications

Terrain navigation sensor processing, signal processing peak detection, and CPU frequency throttling curves.

Subproblems & Recurrence Decomposition3 Phases

🧩Subproblem 1: The Check And The Range

Ask each index one yes-or-no question: do the values fall after i? That is arr[i] > arr[i + 1]. The check reads the next value, so the candidates are 0 to n - 2, and the range is [lo, hi) = [0, n - 1).

Mathematical Recurrence / Code Invariant
# Check: do the values fall after i?
def is_falling(i):
    return arr[i] > arr[i + 1]
lo, hi = 0, n - 1

Step-by-Step Execution Trace Table

StepRange [lo, hi)midarr[mid] > arr[mid + 1]?DecisionNew range [lo, hi)
1[0, 6)310 > 8 → TrueThe values fall after 3, so a peak is at 3 or to its left: hi = mid[0, 3)
2[0, 3)12 > 5 → FalseThe values rise after 1, so a peak is to its right: lo = mid + 1[2, 3)
3[2, 3)25 > 10 → FalseThe values rise after 2, so a peak is to its right: lo = mid + 1[3, 3)
4[3, 3)The range is empty. Lower Bound returns 3, and arr[3] = 10 is the peak.

The trace for arr = [0, 2, 5, 10, 8, 4, 1], step by step:

  • The candidates are the indices 0 to 5, because the check reads the next value. So lo = 0 and hi = 6.
  • Step 1 checks mid = 3: arr[3] = 10 and arr[4] = 8. The check is True, so a peak is at index 3 or to its left. We keep index 3 with hi = mid.
  • Step 2 checks mid = 1: arr[1] = 2 and arr[2] = 5. The check is False, so a peak is to the right. We skip index 1 with lo = mid + 1.
  • Step 3 checks mid = 2: arr[2] = 5 and arr[3] = 10. The check is False, so lo = mid + 1 = 3.
  • Step 4: lo is equal to hi, so the range is empty. Lower Bound returns 3.
Code Shape
Archetype Code Shape
Python
1def is_falling(i: int) -> bool:
2 return arr[i] > arr[i + 1]
3lo = 0
4hi = n - 1
5return binary_search_lower_bound(lo, hi, is_falling)

Conceptual Narrative

🧭 Conceptual Foundation & Pattern Intuition

Extrema Search compares a value with the value next to it, not with a target. The check asks one question about the slope: do the values fall after this index? If they fall, a peak is at this index or to its left. If they rise, a peak is to its right.

⛰️ The Analogy: Walking Uphill In The Dark

Imagine a path over a hill, and you cannot see the top. At any point, you can feel if the next step goes up or down. If the next step goes up, the top is ahead of you. If the next step goes down, you are on the top or you have passed it. You never need to know your height. You only need the direction of the next step.

🔑 Why It Works

The loop keeps one fact: a peak is always at an index from lo to hi. Lower Bound uses the check arr[i] > arr[i + 1]. When every check is False, the values rise to the end, so the last index is a peak. On a mountain, the check is False and then True, so the first True is the top. On a list with several peaks, the check is not False and then True, and the search still returns one peak, not the highest.

  • Setting hi = n while the check reads arr[i + 1]

  • Using the check when two neighbouring values can be equal

  • Returning the value instead of the index

  • In the grid, comparing a cell with its left and right neighbours at the same time

  • In the grid, comparing the first cell of the column instead of its largest cell

Senior SWE Reasoning Architecture

4-Phase Thought Process Model

Pattern Recognition Signals

The 10-second spot

"Its values climb up to one peak and then descend. Return the index of that peak. Solve it in O(log n) time.": a rise-then-fall shape and a logarithmic budget point to Extrema Search.

Formulating the Predicate & Invariants

Turning intuition into a boolean rule

Invariant: a peak is always at an index from lo to hi. The check arr[i] > arr[i + 1] asks if the values fall after i. On a mountain, it is False and then True, so Lower Bound finds the first True, the top. On a list with several peaks, it is not False and then True, and the invariant still holds.

Silent Failure Traps & Edge Cases

Where confident candidates still lose points

  • Setting hi = n while the check reads arr[i + 1]: the last candidate reads past the end, and Python raises an IndexError (arr = [1, 2, 3]). The candidates are 0 to n - 2, so hi = n - 1.

  • Expecting the highest peak: with several peaks the search returns one of them, and arr = [3, 1, 2] returns index 2, not index 0.

The 60-Second Interview Pitch

Say this out loud before you type a single line

"This is Extrema Search. I run Lower Bound with the check arr[i] > arr[i + 1], which asks if the values fall after i. If they fall, a peak is at i or to its left, so Lower Bound keeps mid. If they rise, a peak is to its right, so Lower Bound skips mid. The check reads the next value, so the candidates stop at n - 2, and I call binary_search_lower_bound(0, n - 1, is_falling). When no candidate is True, the values rise to the end, and the last index is the peak. A peak is always between lo and hi, so the search never loses it. The trap is expecting the highest peak: with several peaks, I return one of them. Each pass halves the range, so it is O(log n) time and O(1) space."

Big-O Invariant Derivation

Complexity & Mathematical Proof

TIME COMPLEXITY

O(log N)

Look at the loop in Lower Bound: while lo < hi:. Each pass does one comparison, arr[mid] > arr[mid + 1], and keeps either [lo, mid) or [mid + 1, hi), which is at most half of the range. From N indices the loop runs at most ⌊log2 N⌋ + 1 times with O(1) work each: O(log N) time.

SPACE COMPLEXITY

O(1)

Look at the memory used: the loop is iterative, so the call stack holds one frame. We store only the integers lo, hi and mid. Auxiliary space is O(1).

Formal Recurrence Relation

T(N)=T(N/2)+O(1)⟹O(log⁡N)T(N) = T(N/2) + O(1) ⟹ O(\log N)T(N)=T(N/2)+O(1)⟹O(logN)

Derivation Progression

Slope Detection

delta = arr[mid+1] - arr[mid]

If delta > 0, the values rise after mid, so a peak is to its right. Otherwise a peak is at mid or to its left.

Interval Elimination

lo = mid + 1 or hi = mid

A peak is always at an index from lo to hi, so removing the other part never loses it.

Convergence

lo == hi ⟹ O(log N)

Converges on a peak in at most floor(log2 N) + 1 iterations.

Variable Definitions

NNN

Total number of elements in the mountain array

Memory Architecture & Bounds

🟣 Call Stack

O(1) Iterative

🔵 Auxiliary Heap

O(1) Scalar registers

🟢 Output Space

O(1) Peak index integer

Boundary Best / Worst Cases

Best Case

O(log⁡N)O(\log N)O(logN) — Fixed binary search convergence.

Average Case

O(log⁡N)O(\log N)O(logN).

Worst Case

O(log⁡N)O(\log N)O(logN) — Every pass halves the range.

Recurrence Tree Topology

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

Senior SWE Deconstruction & Hardware Caveats

ARCHITECTURAL SIGNALS & INTERVIEW TRIGGERS

The statement describes a "mountain array" whose values "climb up to one peak and then descend", and asks for the peak's index "in O(log n) time". This is Extrema Search: nothing is compared with a target. The check arr[i] > arr[i + 1] asks if the values fall after i, and Lower Bound finds the first index where they do.

CONSTRAINTS & BOUNDS

The array length is 3≤N≤1053 \le N \le 10^53≤N≤105, with elements up to 10610^6106. The mountain property guarantees that the peak never resides at index 000 or index N−1N - 1N−1. The check reads arr[i + 1], so the candidates are 0 to n - 2, and the search range is lo = 0 and hi = n - 1.

FAANG PRODUCTION TRAPS & EDGE CASES

The card's trap is expecting the highest peak: with several peaks, the search returns one of them. A second trap is setting hi = n, which makes the last candidate read arr[n]. At scale there is one more: the data. With plateaus or equal neighbours the slope check is blind, so either confirm that neighbours differ or fall back to a linear scan. With noisy values, one comparison can point the wrong way, so compare smoothed values or wider gaps instead of single neighbours.

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