Binary search — theory and visualization
Divide a sorted range in half each time until the target is pinned down. This page walks the idea, traces one search step by step, and lists habits that save time in competition.
Overview
Binary search answers questions about a sorted sequence (or any situation where a predicate is false for small values and true for large ones — “binary search on the answer”).
You keep an interval [lo, hi] that must still contain the answer. Each step picks mid, compares or tests, and throws away half of the interval. After about log₂ n steps, only one plausible position remains.
Why sorting matters (array search): The comparison a[mid] vs target tells you whether the target can still live in the left half or only the right half. Without order, that inference is invalid.
Contest angle: Prefer lower_bound / upper_bound on vector when you only need a position — they encode correct edge cases. Hand-written loops are fine if you keep one clear invariant and test n = 0, n = 1, and “all equal.”
How one step works
Assume 0-based indices and a non-decreasing array a.
- Set
loandhiso the answer index is inside[lo, hi](exact meaning depends on your variant: inclusive ends vs half-open interval). mid = lo + (hi - lo) / 2— use this form to avoid overflow on large indices in C++.- If
a[mid] < target, the target (if it exists) lies strictly to the right ofmid, so movelopastmid. - If
a[mid] >= target, the first place that could betarget(or the insert position) is atmidor left, so movehitowardmid. - Stop when the interval has shrunk to the answer.
Different problems use slightly different < vs <= and whether hi is inclusive. Pick one template, write check(mid) or a[mid] logic once, and reuse it.
Step-by-step visualization (classic “first index with value ≥ 7”)
Array a = [1, 3, 5, 7, 9, 11], target x = 7. We want the smallest index i with a[i] >= 7 (same spirit as lower_bound).
Use half-open invariant: lo is always valid (answer in [lo, hi)), hi is past-the-end of the candidate range. Start lo = 0, hi = 6 (length).
| Step | lo | hi | mid | a[mid] | Action |
|---|---|---|---|---|---|
| 0 | 0 | 6 | 3 | 7 | a[mid] >= 7 → answer in left part including mid → hi = mid |
| 1 | 0 | 3 | 1 | 3 | 3 < 7 → answer strictly right of mid → lo = mid + 1 → lo = 2 |
| 2 | 2 | 3 | 2 | 5 | 5 < 7 → lo = mid + 1 → lo = 3 |
| 3 | 3 | 3 | — | — | lo == hi → stop. Answer index 3, value 7. |
If x is not present, you still get the first index where you would insert x to keep order. If x is smaller than everything, answer is 0; if x is larger than everything, answer is n (past the end — often check lo == n as “not found” for strict existence queries).
Tips and tricks (competitive programming)
mid = lo + (hi - lo) / 2: avoids(lo + hi)overflow on large bounds.- Know your invariant: write in a comment what
[lo, hi]or[lo, hi)means and what is impossible outside it. - Prefer STL on sorted
vector:lower_bound,upper_bound,equal_range— fewer off-by-one bugs. lower_bound: first position with value ≥x.upper_bound: first with value >x. Count ofx:upper_bound - lower_bound.- Monotone
check(K): ifcheck(K)is false for smallKand true for largeK, binary search the smallest goodK. Reverse theiffor largest goodK. - Bounds for “search on answer”: start from a definitely bad
loand definitely goodhi(or the reverse), then shrink untilhi - lo == 1— many coders find that easier thanwhile (lo < hi)with ambiguous ends. - Sanity tests:
n = 0,n = 1, all elements equal, target smaller than min / larger than max, answer at index0orn-1. - Time: each step is O(1) or O(n) inside
check— total is O(log n) or O(n log n) respectively; do not hide a linearcheckinside many iterations without noticing. - Floating binary search: fixed number of iterations (e.g. 80–100) often beats fiddly epsilons for geometry or real outputs.
Pseudocode
First index with value ≥ x (0-based, half-open [lo, hi)):
1// Half-open: answer in [lo, hi)2lo = 03hi = n4while lo < hi5 mid = lo + (hi - lo) / 26 if a[mid] >= x7 hi = mid8 else9 lo = mid + 110return lo // insert position; if lo == n, all values < x
Complexity
Each iteration cuts the remaining range by about half.
Complexity Analysis
Time Complexity
O(log n) per search on an array of length n
Space Complexity
O(1) extra
Array must be sorted (or predicate must be monotone for “search on answer”)