datarekha
Patterns June 2, 2026

Binary search is everywhere once you see it

Binary search is not a data structure trick — it is a way of thinking about any monotonic question, and once you internalize it, you see it lurking inside problems that look nothing like sorted arrays.

9 min read · by datarekha · algorithmsbinary-searchproblem-solvingintuition

A shipping company needs to deliver packages across twenty cities in seven days. Each truck has a weight limit, and you can choose that limit. The question is: what is the smallest limit that still gets everything delivered in time?

This is not a binary search problem. Or so it looks.

But watch what happens when you ask a simpler question first: can a truck with capacity C deliver everything in seven days? You simulate the route greedily — load packages until the next one would overflow, then dispatch a new truck for the next day. If you finish in seven or fewer days, the answer is yes. If you need eight or more, no.

Now notice: if capacity C is sufficient, then any capacity larger than C is also sufficient. The feasibility answer is monotone — false, false, false, …, true, true, true, forever. There is a boundary, and that boundary is the answer you want. Binary search finds it in about 20 steps even if C ranges over a million values.

That is the whole idea. Everything else is just recognizing the pattern in disguise.


The predicate is the hard part

The textbook version of binary search is so simple it feels almost insulting: given a sorted array, find a target by repeatedly halving the range. The complexity analysis fits on one line. Most programmers learn it in their first week and never think about it again.

That is a shame, because the textbook version teaches the mechanics while hiding the insight.

The insight is this: binary search is not about sorted arrays. It is about any monotone boolean function over an ordered domain. Wherever you have a predicate f(x) such that f is false for all x below some threshold and true for all x above it (or vice versa), you can binary search for the threshold. The sorted array is just one instantiation of that structure, and a rather uninteresting one.

A predicate is monotone if, once it flips from false to true, it never flips back. In formal terms: if f(x) = true and y > x, then f(y) = true. That is the only structural requirement. The domain does not need to be an array. It needs to be ordered and searchable.

The real skill is looking at a new problem and asking: can I frame a yes/no question over this domain such that the answer is monotone?


The square root is a confession

Here is a small example that reveals the shape clearly. Compute the integer square root of a non-negative integer N — the largest integer k such that k squared is at most N.

You could scan from 1 upward. But that is O(sqrt N) steps. Instead, ask: is k squared greater than N? That predicate is false for small k and true for large k. Binary search between 0 and N finds the boundary in O(log N) steps. For N equal to one billion, that is about 30 iterations instead of 31,623.

This example is almost too clean — but it matters because it strips the disguise away entirely. There is no array. There is no sorted list of square roots to look up. There is just a number line, a monotone question, and a boundary to find.


Why log N feels like magic

Twenty steps. That is all you need to find something in one million candidates. Thirty steps covers one billion. Forty-seven steps covers a hundred trillion.

The reason is simple: every step you take, you cut the remaining candidates exactly in half. After k steps you have eliminated all but N divided by 2 to the power k candidates. When that fraction reaches 1, you are done. Solving for k gives you log base 2 of N.

What makes this feel like magic in practice is the constant factor. Linear search through one million records takes — at memory-bandwidth speeds — something like a millisecond. Binary search through the same million takes perhaps twenty comparisons, which at any reasonable clock speed is under a microsecond. That is a factor of a thousand, not from a clever algorithm, but from asking the question differently.

The more important intuition is about the shape of the work. Linear search has to touch most of the candidates. Binary search never does. It always works on the outline of the answer, never the interior.

Binary search converges on the predicate boundaryStep 1Step 2Step 3Step 4FALSE zoneTRUE zonelohimid → TRUE, hi=midlohimid → FALSE, lo=midlohimid → TRUE, hi=midlohiboundary foundEach step halves the live range. The boundary where the predicate flips is pinpointed in O(log n) steps.All eliminated (gray) → only the live window (colored) needs further probing

Four steps of binary search converging on the predicate boundary. Gray regions are eliminated; the colored window halves each round.


First bad version: the canonical disguise

Version control systems track which commit broke the build. You have N commits; the first K are good, the rest are bad. You want commit K plus one: the first bad one. You could check each commit linearly. Or you could notice that “is this commit bad?” is a monotone predicate — once it flips to true, every subsequent commit is also bad. Binary search across the commit range finds the answer in log N checks.

This is the problem that appears in almost every algorithm interview list, and it is a good one precisely because the sorted-array framing is completely absent. There is no array to search. There is a timeline with a structural property, and binary search exploits that property.

The implementation is essentially identical to classical binary search. The only work you do is writing the predicate — isBad(commitId) — which calls your CI system and returns true or false. Everything else is the same loop.


The boundary has two sides

One thing that trips people up is that the boundary can be approached from either direction depending on what you want.

You can search for the leftmost x such that f(x) is true (the first position where the predicate becomes true). Or you can search for the rightmost x such that f(x) is false (the last position before the predicate flips). These are the same boundary, seen from different sides.

In the shipping capacity problem, you want the smallest C where feasibility is true — leftmost true. In a problem asking for the largest k such that k squared is at most N, you want the rightmost false (or equivalently the leftmost x where k squared exceeds N, then subtract one).

Getting this direction wrong by one is the source of most off-by-one bugs in binary search. The fix is to reason about the invariant explicitly before you write the loop: at every point, lo is a known-false index and hi is a known-true index (or vice versa), and you narrow until they are adjacent. Then you return the one you want.

This invariant-based framing — rather than the “check mid and update lo or hi” incantation — is what separates someone who understands binary search from someone who has memorized a code template.


The real interview test

When interviewers ask a binary search problem that is not “find target in sorted array,” they are probing exactly one thing: can you recognize monotonic structure in a problem that does not announce itself?

The questions that look hard (“find the minimum speed such that you can eat all bananas before the guard returns,” “find the smallest divisor that makes the sum of quotients at most some threshold”) are all easy once you pattern-match to the predicate formulation. The hard part is the first few seconds: resisting the urge to think combinatorially and asking instead — is there a yes/no question I can write whose answer only changes direction once across this domain?

If yes, you binary search for the flip. If no, you need a different technique.


Where you find it in the wild

Production code is full of binary search under other names.

Database indexes use it when resolving range queries on a B-tree (a balanced tree structure optimized for block storage). The tree structure is just a materialized binary search across the key space, with the answers cached in sorted order on disk.

Load testing tools use it when finding the maximum request rate at which a service meets its latency SLA (service-level agreement, the contractual latency target). “Does this service handle 5,000 requests per second under 200 milliseconds p99?” is a monotone predicate — once you exceed capacity, it stays true. Binary search across request rates finds the limit in a handful of load tests rather than a linear sweep.

Compiler optimizers use it when doing binary search on line numbers inside a source file to map a machine-code address back to a source location. The file is effectively a sorted array of line ranges, so classical binary search applies. But the insight that locations can be treated as an ordered searchable domain is the same insight.

Numerical methods call it bisection — given a continuous function that is negative at one endpoint and positive at another, find the zero by bisecting the interval. This is binary search on the real number line. Same predicate structure, same halving, same log convergence.


The one mental move

Everything above reduces to a single mental move: replace “what is the value?” with “is this value good enough?”

Once you phrase it as a yes/no threshold question, you have a predicate. Check whether that predicate is monotone over your domain (does it stay true once it flips?). If it is, set lo and hi to the extremes of your domain, write your loop, and collect the boundary. The complexity is O(log(domain size)) evaluations of the predicate, plus whatever it costs to evaluate the predicate once.

The shipping problem, the square root, the first bad commit, the bisection root-finder, the minimum truck capacity, the minimum eating speed: they are all the same problem. They just wear different clothes.

Binary search is not a trick for sorted arrays. It is a paradigm for any monotone question. And once you see that paradigm, you find it in the architecture of databases, in load testing methodology, in compiler internals, in numerical analysis — everywhere a problem lets you ask “is this threshold too high or too low?” and the answer shifts monotonically as you scan the threshold.

Twenty steps. One million candidates. The same answer.

Skip to content