Skip to content
Back to Home

Binary Search

14 practice problemsInteractive visual guide

1. Why a Recipe Matters

Binary search is unusually easy to almost get right. One reusable recipe leaves more attention for the problem-specific predicate and return value.

2. The Transition-Point Recipe

Reframe the search space as two monotonic regions:

before  before  before  before | after  after  after
                                ^
                          transition point

Define is_before(x) so every “before” candidate comes before every “after” candidate. The values themselves do not need to be booleans; only this classification must be monotonic.

Recipe 1

Find the boundary between “before” and “after”

Example: target = 13, so is_before(i) = nums[i] < 13.
is_before(i) = True
is_before(i) = False

1. Establish the invariant

left is known before; right is known after.

2. Shrink the unknown gap

Move exactly one endpoint to mid without breaking the invariant.

3. Stop when adjacent

left is the last before; right is the first after.

The algorithm searches for a change in a monotonic predicate. It does not need to search for equality inside the loop.
transition_point_recipe(first, last, is_before):
    handle an empty range

    left, right = first, last
    handle left already being "after"    # the whole range is after
    handle right still being "before"    # the whole range is before

    while right - left > 1:
        mid = left + (right - left) // 2
        if is_before(mid):
            left = mid
        else:
            right = mid

    # left  = last "before"
    # right = first "after"
    return whichever boundary the problem asks for

The loop never changes:

  • left remains known “before,” and right remains known “after.”
  • mid is strictly between them, so every iteration makes progress.
  • When they are adjacent, left and right identify the transition.

For classic search, use is_before(i) = nums[i] < target. Then right is the first value >= target; check it for equality. For an upper bound, use nums[i] <= target instead.

3. Practice the Recipe on Real Problems

For each problem, first state the “before” region, the “after” region, and whether the answer comes from left, right, or a final validation. Rotated arrays, valley bottoms, and overtaking points change those choices—not the loop.

4. Reusable Idea: Grid Flattening

If an R x C grid is sorted in complete row-major order, imagine it as one virtual sorted array of length R * C. Do not allocate that array; translate indices only when reading a cell:

  • Grid to virtual index: i = r * C + c.
  • Virtual index to grid: r = i // C, c = i % C.

Reusable idea

Treat an R × C grid as one array

0
1
3
4
6
7
9
11
12
13
21
31

grid[1][2] = 9

i=0
0
i=1
1
i=2
3
i=3
4
i=4
6
i=5
7
i=6
9
i=7
11
i=8
12
i=9
13
i=10
21
i=11
31

i = 1 × 4 + 2 = 6

Grid → virtual index

i = r * C + c

Virtual index → grid

(r, c) = (i // C, i % C)
Binary search the virtual array without copying it. This works only when row-major order is globally sorted, including across row boundaries.

This produces an O(log(RC))O(log(RC)) search with O(1)O(1) extra space. It is valid only when each row is sorted and the last value of one row is smaller than the first value of the next row.

5. Reusable Idea: Exponential Search and Guess-and-Check

When a search range has no known upper bound, probe 1, 2, 4, 8, ... until the predicate changes. The last two probes bracket the transition; then apply the normal recipe inside that interval.

Reusable idea

Double until the transition is bracketed

The unknown transition is now inside (8, 16].

Run the normal transition-point recipe only inside that bracket.

1. Guess

Probe 1, 2, 4, 8, ....

2. Check

Stop when the predicate changes state.

3. Refine

Binary search between the last two probes.

Repeated doubling finds an unknown bound in logarithmic time. It is especially useful before binary-searching a guess-and-check answer range.
left, right = 0, 1
while is_before(right):
    left = right
    right *= 2

# The transition is now in (left, right].
run transition_point_recipe(left, right, is_before)

This pairs naturally with guess-and-check:

  1. Guess a candidate answer.
  2. Check whether it is too small, too large, feasible, or infeasible.
  3. Prove those answers form one monotonic transition.
  4. Binary search for the first or last candidate that satisfies the constraint.

Use this when checking one candidate is much easier than constructing the optimum directly. If the answer bounds are unknown, exponential search can discover them first.

6. Conclusion

The central idea is simple: every binary-search solution can be reframed as finding a transition point. Keep one trusted recipe and spend your problem-solving effort on three questions:

  1. What is the ordered search space?
  2. What does is_before(x) mean, and why is it monotonic?
  3. Does the problem need the last “before,” the first “after,” or a value derived from one?

Two useful extensions cover many less-obvious cases: flatten a globally sorted grid into virtual indices, and use repeated doubling when a search bound is unknown. With those tools, binary search becomes a reusable building block instead of a collection of fragile special cases.

Practice Problems

Beyond Cracking the Coding Interview

Valley Bottom

Medium

A valley-shaped array is an array of integers such that:

Start Solving

2-Array 2-Sum

Medium

You are given two non-empty arrays of integers, sorted_arr and unsorted_arr. The first one is sorted, but the second is not. The goal is to find one element from each array with sum 0. If you can find them, return an array with their indices, starting with the element in sorted_arr. Otherwise, return [-1, -1]. Use O(1) extra space and do not modify the input.

Start Solving

Target Count Divisible By K

Medium

Given a sorted array of integers, arr, a target value, target, and a positive integer, k, return whether the number of occurrences of the target in the array is a multiple of k.

Start Solving

Race Overtaking

Medium

You are given two arrays of positive integers, p1 and p2, representing players in a racing game. The two arrays are sorted, non-empty, and have the same length, n. The i-th element of each array corresponds to where that player was on the track at the i-th second of the race. We know that:

Start Solving

Search in Sorted Grid

Medium

You're given a 2D grid of integers, grid, where each row is sorted (without duplicates), and the last value in each row is smaller than the first value in the following row. You are also given a target value, target. If the target is in the grid, return an array with its row and column indices. Otherwise, return [-1, -1].

Start Solving

Search in Huge Array

Medium

We are trying to search for a target integer, target, in a sorted array of integers (duplicates allowed) that is too big to fit into memory. We can only access the array through an API, fetch(i), which returns the value at index i if i is within bounds or -1 otherwise. Using as few calls to the API as possible, return the index of the target, or -1 if it does not exist. If the target appears multiple times, return any of the indices. There is no API to get the array's length.

Start Solving

Min-Subarray-Sum Split

LeetCodeHard

LeetCode: https://leetcode.com/problems/split-array-largest-sum/

Start Solving

Water Refilling

Medium

We have an empty container with a capacity of a gallons of water and another container with a capacity of b gallons. Return how many times you can pour the second container full of water into the first one without overflowing. Assume that a > b.

Start Solving

Min Pages Per Day

Medium

You have upcoming interviews and have selected specific chapters from BCtCI to read beforehand. Given an array, page_counts, where each element represents a chapter's page count, and the number of days, days, until your interview, determine the minimum number of pages you must read daily to finish on time. Assume that:

Start Solving

Tide Aerial View

Medium

You are provided a series of aerial-view pictures of the same coastal region, taken a few minutes apart. Each picture consists of an n x n binary grid, where 0 represents land (above water) and 1 represents water (below water).

Start Solving