Courses › Coding Interviews › Patterns
Binary Search
Classic search, boundary search, and binary search on the answer.
Binary search halves the search space at each step, giving O(log n). Most candidates know the classic version; interviews test the two variations that trip people up: boundary search and binary search on the answer.
When to use it
- The input is sorted (or rotated sorted)
- You can phrase the problem as "find the first/last position where a condition becomes true"
- The answer lies in a numeric range and a candidate can be checked with a monotonic feasibility test ("can we finish with speed k?")
- Constraints are huge (10⁹+) and you need O(log n)
The one template to remember
Find the first index where condition(i) is true, assuming the condition is false…false, true…true:
def first_true(lo, hi, condition):
# searches [lo, hi); returns hi if no index satisfies the condition
while lo < hi:
mid = (lo + hi) // 2
if condition(mid):
hi = mid # mid might be the answer; keep it
else:
lo = mid + 1 # mid is not the answer
return loEvery variant becomes a choice of condition:
- First element ≥ target:
condition = lambda i: nums[i] >= target - Last element ≤ target:
first_true(0, n, lambda i: nums[i] > target) - 1 - Insert position: same as "first ≥ target"
This form avoids most off-by-one bugs because the loop invariant is simple: the answer is always in [lo, hi].
Binary search on the answer
When asked for the minimum value that works (or maximum), and "works" is monotonic, binary search over the value range:
import math
def min_eating_speed(piles, h):
def can_finish(k):
return sum(math.ceil(p / k) for p in piles) <= h
return first_true(1, max(piles) + 1, can_finish)Signals: "minimum capacity", "smallest maximum", "least time such that…". The check is usually a greedy O(n) pass, giving O(n log range) overall.
Rotated sorted arrays
At any midpoint, one half is sorted. Check whether the target lies within the sorted half's range; if so, search there, otherwise search the other half.
Pitfalls
- Infinite loops from
lo = midwithmid = (lo + hi) // 2— the template above avoids it - Integer overflow in other languages: use
lo + (hi - lo) // 2 - Forgetting to check that the returned index is in range and actually matches
[!TIP] Practice Search in Rotated Sorted Array · Minimum Eating Speed · Time-Based Key-Value Store