Binary Search

Medium
Time: O(log n) or O(log(m*n)) for 2DSpace: O(1)
0/12
problems solved
0%
1.

What is Binary Search?

Binary Search is one of the most powerful techniques in computer science. It reduces search time from O(n) to O(log n) by eliminating half the search space in each step.

Real-World Analogy: The Dictionary

Imagine searching for "inheritance" in a physical dictionary. You wouldn't flip page by page from the start. Instead:

  1. Open somewhere in the middle, land on "M"
  2. "Inheritance" comes before "M" → search left half
  3. Open the left half, land on "F"
  4. "Inheritance" comes after "F" → search right half
  5. Continue until you find "I" section

Each step eliminates half the pages. This is binary search!

Visual Comparison:

Brute Force (Linear Search) - O(n):
[1][2][3][4][5][6][7][8][9][10] Finding 6
↓ ↓ ↓ ↓ ↓ ✓ 6 steps
Binary Search - O(log n):
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] Finding 6
↓ mid=5, 6>5 → right
[6, 7, 8, 9, 10]
↓ mid=8, 6<8 → left
[6, 7]
↓ mid=6, found! 3 steps

Why O(log n)?

  • Each step cuts the search space in HALF
  • n → n/2 → n/4 → n/8 → ... → 1
  • Takes log₂(n) steps to reduce n elements to 1
  • log₂(1,000,000) ≈ 20 steps for a million elements!
2.

When to Use Binary Search

Binary search isn't just for sorted arrays. Recognize these patterns:

1. Sorted Array Lookups

  • Find exact value
  • Find insertion position
  • Find first/last occurrence

2. Rotated Sorted Arrays

  • Array was sorted, then rotated
  • One half is always sorted

3. Binary Search on Answer

  • "Find minimum X such that..."
  • "Find maximum speed/capacity"
  • Search the answer space, not an array!

4. Finding Boundaries

  • First element ≥ target (lower bound)
  • Last element ≤ target (upper bound)
  • First position where condition becomes true

5. Peak/Valley Finding

  • Find local maximum or minimum
  • Find turning point in bitonic array

Recognition Signals:

  • "Sorted array" or "monotonic"
  • "O(log n) required"
  • "Find minimum/maximum that satisfies..."
  • "Minimize the maximum" / "Maximize the minimum"

Key Requirement: There must be a monotonic condition - once it becomes true (or false), it stays that way. This lets us eliminate half the space.

3.

The 4-Step Implementation Framework

Every binary search follows these four steps:

Step 1: Define the Search Space The search space contains all possible values. Define left and right pointers.

[1, 3, 5, 7, 9, 11, 13] target = 7
↑ ↑
left=0 right=6
Search space: indices 0 to 6

Step 2: Narrow the Search Space Compare middle element to target. Eliminate half each iteration.

if target > nums[mid]: left = mid + 1 (search right)
if target < nums[mid]: right = mid - 1 (search left)
if target == nums[mid]: found!

Step 3: Choose Exit Condition

  • while (left <= right) → exits when left > right (exact match)
  • while (left < right) → exits when left == right (boundary finding)

Step 4: Return the Correct Value

  • For exact match: return mid when found, -1 when not found
  • For boundaries: return left (they converge to the answer)

Calculating Midpoint (IMPORTANT):

// WRONG - can overflow if left + right > MAX_INT
int mid = (left + right) / 2;
// CORRECT - no overflow
int mid = left + (right - left) / 2;
4.

Standard Binary Search Template

The classic binary search for finding an exact match.

Walkthrough: Finding 7 in [1, 3, 5, 7, 9, 11, 13]

Initial: left=0, right=6
Iteration 1:
mid = 0 + (6-0)/2 = 3
nums[3] = 7 = target ✓
Return 3

Walkthrough: Finding 4 (not in array)

Initial: left=0, right=6
Iteration 1:
mid = 3, nums[3] = 7
4 < 7 → search left
right = mid - 1 = 2
Iteration 2:
mid = 1, nums[1] = 3
4 > 3 → search right
left = mid + 1 = 2
Iteration 3:
mid = 2, nums[2] = 5
4 < 5 → search left
right = mid - 1 = 1
Exit: left (2) > right (1)
Return -1 (not found)

Key Points:

  • Use left <= right (includes when left == right for single element)
  • Use mid = left + (right - left) / 2 to avoid overflow
  • Both boundaries move: left = mid + 1 and right = mid - 1
Code
Java
5.

Interactive: Binary Search Visualizer

Watch how binary search eliminates half the remaining elements with each comparison.

Binary Search

O(log n) search by halving the search space

Speed:
Target: 11
Sorted Array:
1
0
3
1
5
2
7
3
9
4
11
5
13
6
15
7
17
8
Click Play to search for 11
Mid
Found
Eliminated

Key Insight: Each comparison eliminates half the remaining elements. For n elements, we need at most log₂(n) comparisons.

6.

Edge Cases Deep Dive

Understanding edge cases solidifies your grasp of binary search termination.

Case 1: Empty Array

nums = [], target = 5
left = 0, right = -1 (length - 1)
Condition: left <= right? 0 <= -1? NO
Loop never runs → return -1

Case 2: Single Element Array

nums = [3], target = 3
left = 0, right = 0
Iteration 1:
mid = 0, nums[0] = 3 = target ✓
Return 0
nums = [3], target = 5
left = 0, right = 0
Iteration 1:
mid = 0, nums[0] = 3
5 > 3 → left = mid + 1 = 1
Condition: 1 <= 0? NO → return -1

Case 3: Target Not in Array

nums = [1, 3, 4, 8], target = 2
...after iterations...
left = 1, right = 1
mid = 1, nums[1] = 3
2 < 3 → right = mid - 1 = 0
Now: left = 1, right = 0
Condition: 1 <= 0? NO → exit

Key Insight: When left > right, the pointers have "crossed" - the search space is empty. This is why we use left <= right: we continue searching as long as there's at least one element (when left == right).

Target at Boundaries:

  • Target is first element → works (mid eventually reaches index 0)
  • Target is last element → works (mid eventually reaches last index)
7.

Finding Boundaries - First & Last Occurrence

When duplicates exist, find the first or last occurrence of a value.

Problem: In [1, 2, 2, 2, 3], find first and last index of 2.

Visualization - Find First (Lower Bound):

[1, 2, 2, 2, 3] target=2
L M R mid=2(val=2), could be first, search left
right = mid
[1, 2, 2]
L M R mid=1(val=2), could be first, search left
right = mid
[1, 2]
L R L < R, mid=0(val=1), too small, search right
M left = mid + 1
[2]
LR L == R, done! First occurrence at index 1

Key Insight:

  • For FIRST occurrence: when nums[mid] >= target, it MIGHT be the answer, so right = mid
  • For LAST occurrence: when nums[mid] <= target, it MIGHT be the answer, so left = mid

Loop Condition:

  • Use left < right (not <=)
  • Loop ends when left == right, which is the answer
Code
Java
8.

Search in Rotated Sorted Array

A sorted array that has been rotated at some pivot point.

Example:

Original: [1, 2, 3, 4, 5, 6, 7]
Rotated: [4, 5, 6, 7, 1, 2, 3] (rotated at index 4)

Key Insight: At any mid point, ONE half is ALWAYS sorted!

Visualization:

[4, 5, 6, 7, 1, 2, 3] target=2
L M R
Left half [4,5,6,7]: sorted (nums[L] <= nums[M])
Right half [1,2,3]: contains rotation point
Is target in sorted left half? No (2 < 4)
-> Search right half
[1, 2, 3]
L M R Both halves sorted, mid=2, found!

Decision Logic:

if left half is sorted (nums[left] <= nums[mid]):
if target is in left half (nums[left] <= target < nums[mid]):
search left
else:
search right
else (right half is sorted):
if target is in right half (nums[mid] < target <= nums[right]):
search right
else:
search left
Code
Java
9.

Interactive: Rotated Array Visualizer

See how binary search identifies which half is sorted to decide the search direction.

Search in Rotated Sorted Array

One half is always sorted - use it to decide search direction

Speed:
Target: 0
Rotation point: index 4
Rotated Array: [4,5,6,7 | 0,1,2]
4
0
5
1
6
2
7
3
0
4
1
5
2
6
Click Play to search for 0 in rotated array
Sorted Half
Mid
Found

Key Insight: At any mid point, one half is ALWAYS sorted. Check if target is in the sorted half to decide direction.

10.

Find Minimum in Rotated Array

Find the minimum element in a rotated sorted array.

Key Insight: The minimum is at the rotation point - where the sequence "breaks".

Visualization:

[4, 5, 6, 7, 1, 2, 3]
minimum (rotation point)
If nums[mid] > nums[right]: minimum is in right half
If nums[mid] < nums[right]: minimum is in left half (including mid)

Example:

[4, 5, 6, 7, 1, 2, 3]
L M R mid=7 > right=3 -> min in right
left = mid + 1
[1, 2, 3]
L M R mid=2 < right=3 -> min in left (or mid)
right = mid
[1, 2]
L R mid=1 < right=2 -> right = mid
M
[1]
LR left == right, found minimum!
Code
Java
11.

Binary Search on Answer

Instead of searching in an array, search in a RANGE of possible answers.

When to use:

  • "Find minimum X such that condition is satisfied"
  • "Find maximum speed/capacity/time"
  • "Minimize the maximum" or "Maximize the minimum"

Pattern:

Define: canAchieve(x) -> returns true if x is achievable
Search: Find the minimum/maximum x where canAchieve(x) is true

Example: Koko Eating Bananas Koko has piles of bananas and h hours. Find minimum eating speed k.

piles = [3, 6, 7, 11], h = 8
Speed k=1: hours = 3+6+7+11 = 27 > 8 ✗
Speed k=4: hours = 1+2+2+3 = 8 ≤ 8 ✓
Speed k=3: hours = 1+2+3+4 = 10 > 8 ✗
Minimum speed = 4

Search Space:

  • Minimum possible: 1 (eat at least 1 banana/hour)
  • Maximum possible: max(piles) (finish largest pile in 1 hour)
Code
Java
12.

Interactive: Binary Search on Answer Visualizer

Watch binary search find the minimum eating speed by testing the canFinish predicate.

Binary Search on Answer

Koko Eating Bananas - Find minimum speed to finish in time

Speed:
Time Limit
8 hours
Speed Range
[1, 11]
Banana Piles:
🍌
3
🍌
6
🍌
7
🍌
11
Search Space (Speed):
1Speed11
Click Play to find minimum eating speed

Binary Search on Answer: Instead of searching an array, search the range of possible answers [1, max(piles)]. Use a predicate canFinish(speed) to guide the search.

13.

Find Peak Element

Find a peak element (greater than its neighbors) in an array.

Key Insight: If nums[mid] < nums[mid + 1], a peak MUST exist on the right. Why? Either we keep going up, or we hit a peak.

Visualization:

[1, 2, 3, 1] <- peak at index 2
mid = 1 (value 2)
nums[mid] < nums[mid+1] -> peak on right
[3, 1]
mid = 0 (value 3)
nums[mid] > nums[mid+1] -> peak on left (or mid)
[3]
Found peak at index 2!

Edge Cases:

  • nums[-1] = nums[n] = -∞ (array boundaries are valleys)
  • Multiple peaks may exist; find ANY one

This pattern also applies to:

  • Finding local minimum
  • Finding turning point
  • Bitonic array problems
Code
Java
14.

Search in 2D Matrix

Search in a matrix where rows and columns are sorted.

Type 1: Fully Sorted Matrix Each row starts greater than the previous row ends. Treat as 1D array!

[1, 3, 5, 7 ]
[10, 11, 16, 20]
[23, 30, 34, 60]
Treat as: [1, 3, 5, 7, 10, 11, 16, 20, 23, 30, 34, 60]
Index 5 -> row = 5/4 = 1, col = 5%4 = 1 -> value 11

Type 2: Row & Column Sorted (Search Matrix II) Start from top-right or bottom-left corner.

[1, 4, 7, 11]
[2, 5, 8, 12]
[3, 6, 9, 16]
[10,13, 14, 17]
Searching for 5, start at top-right (11):
11 > 5 -> go left (7)
7 > 5 -> go left (4)
4 < 5 -> go down (5)
Found!
Code
Java
15.

Common Pitfalls and How to Avoid Them

Even experienced developers make these mistakes. Learn them once, avoid them forever.

Pitfall 1: Integer Overflow in Midpoint

// WRONG - overflows when left + right > Integer.MAX_VALUE
int mid = (left + right) / 2;
// CORRECT - mathematically equivalent, no overflow
int mid = left + (right - left) / 2;
// ALSO CORRECT - bit shift
int mid = (left + right) >>> 1; // unsigned right shift

Pitfall 2: Infinite Loop

// WRONG - infinite loop when left + 1 == right
while (left < right) {
int mid = left + (right - left) / 2;
if (condition) {
left = mid; // Never moves when mid == left!
}
}
// FIX 1: Always use mid + 1
left = mid + 1;
// FIX 2: Use ceiling for mid when left = mid
int mid = left + (right - left + 1) / 2; // Rounds UP

Pitfall 3: Wrong Loop Condition

// Use <= for exact match (three-way comparison)
while (left <= right) { // Exits when left > right
if (nums[mid] == target) return mid;
// ... left = mid + 1 OR right = mid - 1
}
// Use < for boundary finding (two-way comparison)
while (left < right) { // Exits when left == right
if (condition) right = mid;
else left = mid + 1;
}

Pitfall 4: Off-by-One in Boundary Updates

Rule of thumb:
- Moving left PAST mid: left = mid + 1
- Keeping mid in search: right = mid
- Excluding mid from search: right = mid - 1

Pitfall 5: Empty Array Not Handled

// WRONG - crashes on empty array
if (nums[left] == target) ...
// CORRECT - check first
if (nums.length == 0) return -1;
16.

Template Summary & Decision Guide

Quick Reference Templates:

Problem TypeLoopLeft UpdateRight UpdateReturns
Exact match<=mid + 1mid - 1mid or -1
First >= x (lower bound)<mid + 1midleft
First > x (upper bound)<mid + 1midleft
Last <= x<mid + 1midleft - 1
Peak element<mid + 1midleft
Rotated min<mid + 1midnums[left]

Decision Tree:

What type of problem?
├─ Find exact value in sorted array?
│ └─ Standard binary search (left <= right)
├─ Find first/last occurrence?
│ └─ Boundary search (left < right)
│ ├─ First: right = mid when nums[mid] >= target
│ └─ Last: left = mid + 1 when nums[mid] <= target
├─ Array is rotated?
│ └─ Check which half is sorted
│ └─ One half is ALWAYS sorted!
├─ Search in 2D matrix?
│ ├─ Fully sorted: treat as 1D array
│ └─ Row/col sorted: start from corner
└─ Find optimal value satisfying condition?
└─ Binary Search on Answer
├─ Define canAchieve(x) predicate
└─ Binary search the answer space

The Golden Rules:

  1. Always use mid = left + (right - left) / 2
  2. Think about which elements to INCLUDE vs EXCLUDE
  3. When in doubt, trace through a small example
  4. Test edge cases: empty array, single element, target not present

Test Your Knowledge

Take a quick 15question quiz to test what you've learned.