Skip to content

64. Find Peak Element

๐Ÿ”— LeetCode Problem: 162. Find Peak Element
๐Ÿ“Š Difficulty: Medium
๐Ÿท๏ธ Topics: Array, Binary Search

Problem Statement

A peak element is an element that is strictly greater than its neighbors.

Given a 0-indexed integer array nums, find a peak element, and return its index. If the array contains multiple peaks, return the index to any of the peaks.

You may imagine that nums[-1] = nums[n] = -โˆž. In other words, an element is always considered to be strictly greater than a neighbor that is outside the array.

You must write an algorithm that runs in O(log n) time.

Example 1:

Input: nums = [1,2,3,1]
Output: 2
Explanation: 3 is a peak element and your function should return the index number 2.

Example 2:

Input: nums = [1,2,1,3,5,6,4]
Output: 5
Explanation: Your function can return either index number 1 where the peak element is 2, or index number 5 where the peak element is 6.

Constraints: - 1 <= nums.length <= 1000 - -2^31 <= nums[i] <= 2^31 - 1 - nums[i] != nums[i + 1] for all valid i


๐ŸŽจ Visual Understanding

The Problem Visualized

Example 1: nums = [1, 2, 3, 1]

Visual:
      3 โ† peak (index 2)
     โ†— โ†˜
    2   1
   โ†—
  1

Peaks: index 2 (value 3)
3 > 2 (left neighbor) โœ“
3 > 1 (right neighbor) โœ“
Example 2: nums = [1, 2, 1, 3, 5, 6, 4]

Visual:
            6 โ† peak (index 5)
           โ†— โ†˜
      2   5   4
     โ†— โ†˜ โ†—
    1   1 3
   โ†—
  1

Peaks: index 1 (value 2) OR index 5 (value 6)
Both are valid answers!
Edge cases:

Single element: [5]
  Index 0 is peak (no neighbors)

Increasing: [1, 2, 3, 4, 5]
  Index 4 is peak (5 > 4, and 5 > -โˆž)

Decreasing: [5, 4, 3, 2, 1]
  Index 0 is peak (5 > -โˆž, and 5 > 4)

All equal invalid (nums[i] != nums[i+1])

๐Ÿšจ CRITICAL INSIGHT - Why Binary Search Works

The Key Pattern!

Amazing Observation:
  A peak ALWAYS exists!
  Even if no obvious peak, edges can be peaks!

Why?
  nums[-1] = -โˆž (conceptually)
  nums[n] = -โˆž (conceptually)

  So first element > -โˆž on left
  And last element > -โˆž on right

  At least one peak guaranteed!

Binary Search Insight:
  At any position mid:
    If nums[mid] < nums[mid + 1]:
      We're on "upward slope"
      Peak MUST exist to the right! โ†’

    If nums[mid] > nums[mid + 1]:
      We're on "downward slope"
      Peak MUST exist to the left! โ†
      (mid itself could be peak)

We can eliminate half at each step!

The Upward vs Downward Slope Decision

Case 1: Upward Slope (nums[mid] < nums[mid + 1])
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

  [1, 2, 1, 3, 5, 6, 4]
        โ†‘  โ†‘
       mid mid+1
       1 < 3 (upward)

  Since going up, and right boundary is -โˆž,
  there MUST be a peak to the right!

  Either:
    - Continues up and hits right edge (peak!)
    - Goes up then down (peak in between!)

  Search right: left = mid + 1

Case 2: Downward Slope (nums[mid] > nums[mid + 1])
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

  [1, 2, 1, 3, 5, 6, 4]
              โ†‘  โ†‘
             mid mid+1
             6 > 4 (downward)

  Since going down, and left boundary is -โˆž,
  there MUST be a peak at mid or to the left!

  Either:
    - mid is the peak
    - Peak exists to the left

  Search left: right = mid

Visual Proof:
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

Upward slope:
       ?
      โ†— or โ†— โ†˜   (peak guaranteed on right)
  mid โ†—     โ†—

Downward slope:
  โ†— โ†˜ or  โ†˜      (peak at mid or left)
    mid   mid

Why This Works - Proof

Claim: Peak always exists on the side we search

Proof for Upward (nums[mid] < nums[mid+1]):

  We search right half: [mid+1, right]

  Case A: Values keep increasing to right edge
    โ†’ Right edge is peak (greater than -โˆž)

  Case B: Values eventually decrease
    โ†’ Before decrease, there's a peak

  Either way, peak exists on right! โœ“

Proof for Downward (nums[mid] > nums[mid+1]):

  We search left half: [left, mid]

  Case A: mid is peak (greater than both neighbors)
    โ†’ Found it!

  Case B: Values increase from left
    โ†’ Before mid, there's a peak

  Case C: mid is at left edge
    โ†’ mid is peak (greater than -โˆž)

  Either way, peak exists on left or at mid! โœ“

This guarantees we'll find a peak!

๐ŸŽฏ Approach 1: Linear Search (Brute Force)

The Most Natural Thinking ๐Ÿ’ญ

Core Logic:

Check each element:
  If greater than both neighbors, it's a peak
  Return that index

Implementation

public int findPeakElement(int[] nums) {
    int n = nums.length;

    // Single element
    if (n == 1) return 0;

    // Check first element
    if (nums[0] > nums[1]) return 0;

    // Check last element
    if (nums[n - 1] > nums[n - 2]) return n - 1;

    // Check middle elements
    for (int i = 1; i < n - 1; i++) {
        if (nums[i] > nums[i - 1] && nums[i] > nums[i + 1]) {
            return i;
        }
    }

    return -1;  // Should never reach
}

โฐ Time: O(n) - Check every element
๐Ÿ’พ Space: O(1) - Only variables

โŒ Problem: Doesn't meet O(log n) requirement!


๐ŸŽฏ Approach 2: Binary Search (Optimal) โญ

Better Approach ๐Ÿ’ก

๐Ÿง  The Core Insight

Key Insight:
  At any mid, we can determine which side has a peak

  If ascending (mid < mid+1): peak on right
  If descending (mid > mid+1): peak on left or at mid

  Eliminate half each time!

The Strategy:

Binary Search for Peak:

1. while (left < right):
   a. mid = left + (right - left) / 2
   b. If nums[mid] < nums[mid + 1]:
      Ascending, peak on right
      left = mid + 1
   c. Else:
      Descending, peak on left or at mid
      right = mid
2. return left

Implementation

public int findPeakElement(int[] nums) {
    int left = 0;
    int right = nums.length - 1;

    while (left < right) {
        int mid = left + (right - left) / 2;

        // Compare mid with its right neighbor
        if (nums[mid] < nums[mid + 1]) {
            // Ascending slope, peak must be on the right
            left = mid + 1;
        } else {
            // Descending slope, peak is at mid or on the left
            right = mid;
        }
    }

    // When left == right, we've found a peak
    return left;
}

โฐ Time: O(log n) - Binary search
๐Ÿ’พ Space: O(1) - Only pointers

๐Ÿ” Dry Run

Example 1: nums = [1, 2, 3, 1]

Goal: Find any peak

Initial: left = 0, right = 3
         [1, 2, 3, 1]
          โ†‘        โ†‘
        left     right

Iteration 1:
  mid = 0 + (3 - 0) / 2 = 1
  nums[1] = 2, nums[2] = 3
  2 < 3 (ascending)
  Peak on right

  left = 2
  [1, 2, 3, 1]
           โ†‘  โ†‘
         left right

Iteration 2:
  mid = 2 + (3 - 2) / 2 = 2
  nums[2] = 3, nums[3] = 1
  3 > 1 (descending)
  Peak at mid or left

  right = 2
  [1, 2, 3, 1]
           โ†‘
        left/right

Loop ends (left == right)
return 2 โœ“

Verification: nums[2] = 3
  3 > 2 (left) โœ“
  3 > 1 (right) โœ“
  Peak! โœ“

Example 2: nums = [1, 2, 1, 3, 5, 6, 4]

Initial: left = 0, right = 6
         [1, 2, 1, 3, 5, 6, 4]
          โ†‘                 โ†‘
        left              right

Iteration 1:
  mid = 3
  nums[3] = 3, nums[4] = 5
  3 < 5 (ascending)
  Peak on right

  left = 4
  [1, 2, 1, 3, 5, 6, 4]
                 โ†‘     โ†‘
               left  right

Iteration 2:
  mid = 5
  nums[5] = 6, nums[6] = 4
  6 > 4 (descending)
  Peak at mid or left

  right = 5
  [1, 2, 1, 3, 5, 6, 4]
                 โ†‘  โ†‘
              left right

Iteration 3:
  mid = 4
  nums[4] = 5, nums[5] = 6
  5 < 6 (ascending)
  Peak on right

  left = 5
  [1, 2, 1, 3, 5, 6, 4]
                    โ†‘
                 left/right

Loop ends
return 5 โœ“

Verification: nums[5] = 6
  6 > 5 (left) โœ“
  6 > 4 (right) โœ“
  Peak! โœ“

Example 3: nums = [1] (single element)

Initial: left = 0, right = 0

Loop condition: left < right
  0 < 0? False
  Loop doesn't run

return 0 โœ“

Single element is always a peak!

Example 4: nums = [1, 2, 3, 4, 5] (increasing)

Initial: left = 0, right = 4

Iteration 1:
  mid = 2
  nums[2] = 3, nums[3] = 4
  3 < 4, go right
  left = 3

Iteration 2:
  mid = 3
  nums[3] = 4, nums[4] = 5
  4 < 5, go right
  left = 4

Loop ends (left == right == 4)
return 4 โœ“

nums[4] = 5 > nums[3] = 4 โœ“
nums[4] = 5 > -โˆž (right boundary) โœ“
Peak at right edge!

Example 5: nums = [5, 4, 3, 2, 1] (decreasing)

Initial: left = 0, right = 4

Iteration 1:
  mid = 2
  nums[2] = 3, nums[3] = 2
  3 > 2, go left or mid
  right = 2

Iteration 2:
  mid = 1
  nums[1] = 4, nums[2] = 3
  4 > 3, go left or mid
  right = 1

Iteration 3:
  mid = 0
  nums[0] = 5, nums[1] = 4
  5 > 4, go left or mid
  right = 0

Loop ends
return 0 โœ“

nums[0] = 5 > -โˆž (left boundary) โœ“
nums[0] = 5 > nums[1] = 4 โœ“
Peak at left edge!

๐ŸŽฏ Why This Works - Deep Dive

The Loop Condition: while (left < right)
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

Similar to "Find Minimum" pattern:
  Converge to single element
  That element is guaranteed to be a peak

The Comparison: nums[mid] vs nums[mid + 1]
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

We check the SLOPE at mid:
  - Upward slope โ†’ peak ahead
  - Downward slope โ†’ peak behind or here

Why compare with mid + 1 (not mid - 1)?
  Consistent direction checking
  Always safe (mid < right guarantees mid + 1 exists)

The Asymmetric Update:
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

Ascending: left = mid + 1
  mid is NOT a peak (smaller than mid+1)
  Safe to exclude mid

Descending: right = mid
  mid COULD be a peak
  Must keep it in range

Same pattern as "Find Minimum"!

Why Peak Always Exists:
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

Mathematical proof:

1. Array has at least 1 element
2. Boundaries are conceptually -โˆž
3. Any local maximum is a peak

Process:
  Start at left edge (> -โˆž)
  If always increasing โ†’ right edge is peak
  If decreases โ†’ local max before decrease is peak
  If oscillates โ†’ multiple peaks exist

At least one peak guaranteed! โœ“

Time Complexity:
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

Each iteration: O(1)
Search space halves: O(log n) iterations
Total: O(log n) โœ“

Much better than O(n) linear search!

Why Not Compare with Both Neighbors?

// Alternative (more intuitive but same result):
if (nums[mid - 1] < nums[mid] && nums[mid] > nums[mid + 1]) {
    return mid;  // Found peak
}

// Issues:
// 1. Need to handle mid == 0 edge case
// 2. Need to handle mid == n-1 edge case
// 3. More code, same complexity

// Our approach is cleaner:
// Just compare with mid + 1
// No edge case handling needed
// Converges to peak automatically

โš ๏ธ Common Mistakes to Avoid

Mistake 1: Wrong loop condition

// โŒ WRONG
while (left <= right) {
    if (nums[mid] > nums[mid + 1]) {
        right = mid;  // Infinite loop!
    }
}

// โœ“ CORRECT
while (left < right) {
    if (nums[mid] > nums[mid + 1]) {
        right = mid;
    }
}

Mistake 2: Wrong pointer update

// โŒ WRONG - Might skip peak
if (nums[mid] > nums[mid + 1]) {
    right = mid - 1;  // Skip mid!
}

// โœ“ CORRECT - Keep mid
if (nums[mid] > nums[mid + 1]) {
    right = mid;  // Mid might be peak
}

Mistake 3: Comparing with wrong neighbor

// โŒ WRONG - Need boundary checks
if (nums[mid] > nums[mid - 1]) {
    // What if mid == 0? Crash!
}

// โœ“ CORRECT - Always safe
if (nums[mid] < nums[mid + 1]) {
    // mid + 1 always exists (mid < right)
}

Mistake 4: Returning wrong value

// โŒ WRONG
return nums[left];  // Returns value, not index

// โœ“ CORRECT
return left;  // Returns index

Mistake 5: Early return on found peak

// โŒ UNNECESSARY (but not wrong)
if (nums[mid] > nums[mid-1] && nums[mid] > nums[mid+1]) {
    return mid;  // Found peak
}
// More code, same result

// โœ“ SIMPLER - Let convergence find it
// Just the ascending/descending checks

๐ŸŽฏ Pattern Recognition

Problem Type: Binary Search - Find Peak
Core Pattern: Slope-Based Half Elimination

When to Apply:
โœ“ Need to find peak element
โœ“ Array not fully sorted
โœ“ Need O(log n) time
โœ“ Any peak is acceptable
โœ“ Neighbors comparison property

Recognition Keywords:
- "Peak element"
- "Greater than neighbors"
- "Any peak"
- O(log n) complexity
- Can return any valid answer

Similar Problems:
- Find Minimum in Rotated Sorted Array (LC 153)
- Find Peak Element II (LC 1901) - 2D version
- Peak Index in Mountain Array (LC 852)

Key Difference from Other BS:
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Classic Binary Search:                     โ”‚
โ”‚   - Array fully sorted                     โ”‚
โ”‚   - Exact target search                    โ”‚
โ”‚                                            โ”‚
โ”‚ Find Peak (This Problem):                 โ”‚
โ”‚   - Array not sorted                       โ”‚
โ”‚   - Find local maximum                     โ”‚
โ”‚   - Use slope to decide direction          โ”‚
โ”‚   - Any valid answer works                 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Slope comparison is the KEY!

๐Ÿง  Interview Strategy

Step 1: "Find peak โ†’ Check slope โ†’ Binary search"
Step 2: "Compare mid with mid+1 to determine slope"
Step 3: "Ascending โ†’ peak on right; Descending โ†’ peak on left/mid"
Step 4: "Converge using while (left < right)"
Step 5: "Return left when converged"

Key Points to Mention:
- Peak always exists (boundary = -โˆž)
- Check slope: mid vs mid+1
- Ascending: left = mid + 1 (exclude mid)
- Descending: right = mid (keep mid)
- Loop: while (left < right)
- Return: left (index, not value)
- Time: O(log n), Space: O(1)
- Any peak is valid answer

Why This Approach?
"A peak is guaranteed to exist because the boundaries are
conceptually negative infinity. At any position, I can check
the slope by comparing nums[mid] with nums[mid+1]. If it's
ascending, a peak must exist to the right (either it keeps
going up to the edge, or it goes down creating a peak). If
it's descending, the peak is either at mid or to the left.
This lets me eliminate half the array each iteration, giving
O(log n) time."

Why Compare with mid+1?
"Comparing with mid+1 tells me the slope direction clearly.
If nums[mid] < nums[mid+1], I'm on an upward slope. If
nums[mid] > nums[mid+1], I'm on a downward slope. This is
simpler and safer than comparing with both neighbors."

๐Ÿ“ Quick Revision Notes

๐ŸŽฏ Core Concept:

Find Peak Element: Peak always exists! Check slope at mid: compare nums[mid] with nums[mid+1]. Ascending (mid < mid+1) โ†’ peak on right. Descending (mid > mid+1) โ†’ peak on left/mid. Converge with while (left < right). Return index!

โšก Quick Implementation:

class Test {
  public int findPeakElement(int[] a) {
    int len = a.length;
    int left = 0;
    int right = len - 1;    

    // Same template as Find Minimum in Rotated Sorted Array (left < right and right = mid)
    while (left < right) {      
      int mid = left + (right - left) / 2;

      if(mid + 1 < len && a[mid] < a[mid + 1]) { // since they asked strictly increasing
        // check right side
        // go right side since there is an element greater than existing element being taken
        left = mid + 1;
      } else {
        right = mid; // mid also can be answer
      }
    }

    return left;
  }

  public static void main(String[] args) {
    Test t = new Test();
    System.out.println(t.findPeakElement(new int[] {1,2,3,1}) == 2);
    System.out.println(t.findPeakElement(new int[] {1,2,1,3,5,6,4}) == 5);
    System.out.println(t.findPeakElement(new int[] {1}) == 0);
    System.out.println(t.findPeakElement(new int[] {1, 2}) == 1);
    System.out.println(t.findPeakElement(new int[] {2, 1}) == 0);
    System.out.println(t.findPeakElement(new int[] {1, 2, 3, 4, 5}) == 4);
    System.out.println(t.findPeakElement(new int[] {5, 4, 3, 2, 1}) == 0);
    System.out.println(t.findPeakElement(new int[] {3, 2, 1, 2, 3}) == 4);
  }
}

๐Ÿ”‘ Key Insights:

  • Pattern: Find Peak via Slope Detection
  • Guarantee: Peak always exists (boundary = -โˆž)
  • Compare: nums[mid] vs nums[mid + 1] (slope)
  • Ascending: left = mid + 1 (peak on right)
  • Descending: right = mid (peak on left or mid)
  • Loop: while (left < right) (converge)
  • Return: left (index, not value!)
  • Time: O(log n), Space: O(1)

๐ŸŽช Memory Aid:

"Check the slope! Up โ†’ go right, Down โ†’ keep mid!"
Think: "Slope decides direction, converge to peak!"

๐Ÿ’ก The Key Insight:

At mid:
  nums[mid] < nums[mid + 1]:
    Ascending slope โ†—
    Peak on right
    left = mid + 1

  nums[mid] > nums[mid + 1]:
    Descending slope โ†˜
    Peak on left or at mid
    right = mid

โš ๏ธ Critical Details:

1. Loop: while (left < right) โ† Not <=
2. Compare: nums[mid] vs nums[mid + 1]
3. Ascending: left = mid + 1
4. Descending: right = mid โ† Not mid - 1!
5. Return: left โ† Index, not value!
6. Safe: mid + 1 always exists (mid < right)

๐Ÿ”ฅ Why Peak Always Exists:

Boundaries are -โˆž:
  nums[-1] = -โˆž
  nums[n] = -โˆž

So:
  First element > -โˆž
  Last element > -โˆž

If increasing: last is peak
If decreasing: first is peak
If mixed: local max is peak

Always at least one peak! โœ“

๐Ÿ’ก Visual Pattern:

Ascending slope:
     ?
    โ†— (peak somewhere ahead)
  mid

Descending slope:
  โ†˜ (peak at mid or behind)
  mid

Check slope โ†’ decide direction!

๐Ÿงช Edge Cases

Case 1: Single element

Input: nums = [1]
Output: 0
(Always a peak)

Case 2: Two elements - increasing

Input: nums = [1, 2]
Output: 1
(Right edge is peak)

Case 3: Two elements - decreasing

Input: nums = [2, 1]
Output: 0
(Left edge is peak)

Case 4: All increasing

Input: nums = [1, 2, 3, 4, 5]
Output: 4
(Right edge is peak)

Case 5: All decreasing

Input: nums = [5, 4, 3, 2, 1]
Output: 0
(Left edge is peak)

Case 6: Multiple peaks

Input: nums = [1, 2, 1, 3, 5, 6, 4]
Output: 1 or 5
(Any peak is valid)

Case 7: Valley in middle

Input: nums = [3, 2, 1, 2, 3]
Output: 0 or 4
(Peaks at edges)

All handled correctly! โœ“


  • Find Minimum in Rotated Sorted Array (LC 153) - Similar slope logic
  • Peak Index in Mountain Array (LC 852) - Simplified version
  • Find Peak Element II (LC 1901) - 2D version

Happy practicing! ๐ŸŽฏ

Note: This is a beautiful application of binary search to non-sorted arrays! The slope-based decision is elegant and powerful. Master this pattern!