Binary Search
Discard half of the remaining candidates on each step by testing a monotonic condition, turning O(n) scans into O(log n) and letting you search over answers.
Instinct Sorted data, a rotated array, or find the min/max X that works where a yes/no test flips only once - halve the search space every step.
Memory hack Find the fence - every candidate reads NO NO NO YES YES, and binary search just walks to where the fence stands.
At a glance
When to use it
- The data is sorted, rotated sorted, or otherwise ordered
- A yes/no test is false up to some point and true after it
- You need the minimum or maximum value (speed, capacity, days) that works
- The problem demands O(log n) time
Key idea
Phrase the question as a monotonic predicate (FFFFTTTT) and halve the candidates each step to find the first true, cutting an O(n) scan to O(log n). The candidates can be answers instead of indices: binary search on the answer finds Koko's slowest workable speed in O(n log maxPile).
Typical complexity
O(log n) time, O(1) space; O(n log range) when searching on the answer
The instinct
Binary search is not really about sorted arrays; it is about a monotonic predicate - a yes/no question that is false for a prefix of candidates and true for everything after (FFFFTTTT). In a sorted array the question is "is a[i] >= target?". In Find Minimum in Rotated Sorted Array it is "is a[i] <= a[last]?". In Koko Eating Bananas the candidates are speeds and the question is "can she finish in h hours at this speed?". Once you can phrase the problem as FFFFTTTT, you find the first T in O(log n) checks.
Recognise it
| Signal in the problem | Why it points here |
|---|---|
| "sorted array", "return the index where it would be inserted" | Lower bound: first index with a[i] >= target. |
| "first and last position of target" | Two boundary searches; upper = lowerBound(target + 1) - 1. |
| "rotated sorted array" | One half around mid is always sorted; compare mid with the right end. |
| "peak element", "mountain array" | The slope is the predicate: if a[mid] < a[mid + 1], a peak lies to the right. |
| "minimum speed / capacity / days such that..." | Binary search on the answer with a feasibility check. |
| "must run in O(log n)" | The interviewer is practically naming the pattern. |
| "each row starts after the previous row ends" (2D matrix) | It is one sorted array of m·n cells in disguise. |
| "pick an index with probability proportional to weight" | Prefix sums are sorted; search for the first prefix greater than a random number. |
Not this pattern if...
- The data is unsorted and you need one lookup - a hash set is O(1); sorting first costs O(n log n).
- The predicate is not monotonic (works at 5, fails at 6, works at 7) - binary search returns nonsense; think DP or greedy.
- You need the k-th largest of an unsorted array - quickselect or a heap is the natural fit.
- You must report every matching element - locate the boundary, then the rest is linear.
Memory hack
Find the fence. Line up every candidate and label it NO or YES. If all the NOs come before all the YESes, there is a single fence between them. Each probe at mid tells you which side of the fence you are on, so you throw away the half that cannot contain it.
Analogy - the oven dial. You want the lowest oven temperature that bakes a cake within 30 minutes. Every temperature below some point fails and every temperature above it succeeds. You would never try 1°, 2°, 3°...; you try the middle of the dial, then the middle of the remaining half, and pin it down in a handful of bakes.
Say it out loud:
- "My predicate is ___, and over
[lo, hi]it is false then true." - "I want the first true: if
midis true I keep it (hi = mid), otherwise I drop it (lo = mid + 1)." - "The loop ends when
lo == hi; I confirmhistarted at a value that is definitely feasible, or check the result afterwards."
How it works
Keep a range that is guaranteed to contain the answer and shrink it by half each step, never discarding the answer itself. With the half-open convention [lo, hi), hi = n means "not found / insert at the end".
Lower bound of 7 in [1, 3, 5, 7, 7, 9]:
| lo | hi | mid | a[mid] | a[mid] >= 7? | Action |
|---|---|---|---|---|---|
| 0 | 6 | 3 | 7 | yes | hi = 3 (mid might be the answer) |
| 0 | 3 | 1 | 3 | no | lo = 2 |
| 2 | 3 | 2 | 5 | no | lo = 3 |
| 3 | 3 | - | - | - | stop: first 7 is at index 3 |
Searching on the answer is the same loop. The only differences are that lo..hi is a range of possible answers (speeds, capacities, days) and the predicate is a function you write, usually a greedy O(n) simulation.
Java template
import java.util.function.LongPredicate; class BinarySearchTemplates { // First index in [0, n] with a[i] >= target (n if none). // Insert position = lowerBound; first occurrence = lowerBound if a[i] == target; // last occurrence = lowerBound(a, target + 1) - 1. static int lowerBound(int[] a, int target) { int lo = 0, hi = a.length; // search space [lo, hi) while (lo < hi) { int mid = lo + (hi - lo) / 2; // avoids int overflow of (lo + hi) if (a[mid] >= target) hi = mid; // mid could be the answer: keep it else lo = mid + 1; // mid is too small: discard it } return lo; } // Binary search on the answer: smallest x in [lo, hi] with ok(x) true. // Needs ok to be monotonic (false...false true...true) and ok(hi) to be true. static long minFeasible(long lo, long hi, LongPredicate ok) { while (lo < hi) { long mid = lo + (hi - lo) / 2; if (ok.test(mid)) hi = mid; else lo = mid + 1; } return lo; } // Mirror image: largest x in [lo, hi] with ok(x) true (true...true false...false). static long maxFeasible(long lo, long hi, LongPredicate ok) { while (lo < hi) { long mid = lo + (hi - lo + 1) / 2; // round UP, otherwise lo = mid can loop forever if (ok.test(mid)) lo = mid; else hi = mid - 1; } return lo; } // Example feasibility check (Koko Eating Bananas): finish all piles in h hours at speed k? // Usage: minFeasible(1, maxPile, k -> canFinish(piles, k, h)) static boolean canFinish(int[] piles, long k, long h) { long hours = 0; for (int p : piles) hours += (p + k - 1) / k; // ceiling division return hours <= h; } }
Complexity
- Search in an array: O(log n) time, O(1) space for the iterative version.
- Search on the answer: O(log(hi - lo) × cost of the check) - for Koko that is O(n log maxPile).
- 2D matrix as 1D: O(log(m·n)), mapping
midto(mid / cols, mid % cols). - Median of Two Sorted Arrays: O(log min(m, n)) by binary searching the partition point in the shorter array.
Variations
- Bounds on sorted data - lower/upper bound and exact match. Search Insert Position, Find First and Last Position of Element in Sorted Array.
- Rotated arrays - decide which half is sorted, then whether the target lies inside it. Search in Rotated Sorted Array, Find Minimum in Rotated Sorted Array.
- Slope / peak - compare
midwithmid + 1. Find Peak Element; Find in Mountain Array finds the peak, then searches the ascending and descending sides separately. - Search on the answer - minimise or maximise a parameter with a feasibility test. Koko Eating Bananas.
- Flattened 2D - one search over the virtual array. Search a 2D Matrix.
- Prefix sums + search - weighted sampling. Random Pick with Weight.
- Partition search - cut both arrays so the left halves together hold half the elements. Median of Two Sorted Arrays.
Common mistakes
- Mixing conventions:
hi = nwithwhile (lo <= hi), orhi = n - 1withhi = mid. Pick inclusive or half-open and keep every line consistent. - Bad answer bounds: starting Koko's speed at 0 (division by zero), or choosing an
hithat is not actually feasible. - Summing in
intinside the feasibility check - hours, days and weights overflow quickly; uselong. - Applying the plain rotated-array logic to arrays with duplicates: when
a[mid] == a[hi]you cannot tell which side is sorted, so shrinkhiby one (worst case O(n)). - Writing
(lo + hi) / 2with large indices or answer ranges; uselo + (hi - lo) / 2.
The infinite-loop trap: when the update is lo = mid, a round-down mid can equal lo forever once two candidates remain. Whenever you keep mid on the left side, round mid up. Dry-run a two-element range before you say "done".
All practice problems
10 problems on this site use this pattern, easiest first. Solve them in order and say the instinct out loud before you code.