Binary search on the answer, not the array

There is no array to search here. The trick is that feasibility is monotonic: if a capacity works, every larger one works too. So the answers form a sorted sequence of no-no-no-yes-yes, and binary search finds the boundary — with an O(n) feasibility check in place of an array lookup.

Binary searchCoding problemMedium

Step through it

What to watch

  • The thing being searched is a range of answers, not the input.
  • Each probe costs a full O(n) pass — the feasibility check.
  • The predicate flips exactly once, which is what makes it searchable.

Say this out loud

"I binary search the answer rather than an array. The predicate is 'can this capacity finish in D days', which I can check in one pass, and it is monotonic - if a capacity works, anything bigger works. So the feasible capacities are a suffix, and I search for the first one. Bounds are max weight to total weight, so it is O(n log sum)."

Overview

Binary search can find the smallest feasible answer when a yes/no test changes only once as the candidate grows. It applies to capacities, speeds, and limits when you can define that monotone test and a valid search range.

Run it

The probe table: five probes over a range of forty-six candidates.

1Python
Output

Monotonicity is what licenses the search, so check it rather than assume it.

2Python
Output

The same shape on a different question, to show it is a pattern and not a trick.

3Python
Output

Apply the same binary search to a different domain: the minimum eating speed to finish a set of piles within a given number of hours.

4Python
Output

Recognising it

The tell is a question of the form "what is the smallest X such that something is possible" — smallest capacity, minimum speed, fewest days, largest minimum distance. There is no sorted array in the input, which is why the shape gets missed.

What is sorted is the answer space. If you can write a function feasible(x) that is False for every x below the answer and True for every x at or above it, then the sequence feasible(lo) ... feasible(hi) is sorted — and finding where it flips is exactly binary search.

The three things to establish before writing the loop

The predicate. Here, "can capacity c deliver everything in D days?" Greedily load until the next package would overflow, then start a new day. One pass, O(n), and greedy is optimal for it because leaving room spare can never reduce the day count.

Monotonicity. A bigger ship cannot need more days. State it — this is the step that makes the search valid, and an interviewer will ask why you are allowed to binary search something with no array in it.

The bounds. lo = max(weights), because a package must fit in one trip. hi = sum(weights), because that always finishes in one day. Getting the low bound wrong — starting at 1, or at 0 — produces a search over capacities that can never work, and the loop returns an infeasible answer rather than looping forever, which is worse.

Cost, and the shape of it

O(n log(sum − max)): a logarithmic number of probes, each costing a linear pass. Note that the log is over the magnitude of the answer range rather than the size of the input, which is unusual and worth saying — it means the complexity depends on the numbers, not just on how many there are.

The editor below prints the probe table. Ten packages give a range of 46 candidate capacities and the search settles it in five probes.

The same shape, four other questions

Koko eating bananas — smallest eating speed to finish in H hours. Identical, with ceil(pile / speed) as the per-pile cost.

Split an array into k subarrays minimising the largest sum. The predicate is "can we do it with all parts at most m", and it is the same greedy pass.

Aggressive cows / maximum minimum distance — place k items as far apart as possible. The monotonicity flips direction: large distances are infeasible, so you search for the last True instead of the first.

The square root of an integer, or any inverse of a monotonic function. Once the pattern is visible, "is there a monotonic predicate here?" becomes a routine question to ask of any minimisation problem.

Edge cases to raise

Volunteering these is most of what separates a correct answer from a good one.

Verify the monotonicity. If the predicate flips more than once, binary search returns a boundary that means nothing. Printing it either side of the answer is cheap insurance.

The bounds must bracket the answer. Too low and the search can return an infeasible value; too high only costs a probe or two. When in doubt, err high.

The log is over the magnitude of the answer range, not the input length - so the complexity depends on the size of the numbers. Worth stating, because it is unusual.

Sources and next steps

How the code works

The probe table, the monotonicity that licenses the search, and the same technique applied to a second problem to show it is a shape rather than a trick.

How the code works

  1. lo, hi = max(weights), sum(weights)The bounds are part of the answer. Below max no capacity can work at all, and sum always finishes in one day, so the boundary is guaranteed to be inside.
  2. if load + w > capacity: days += 1The feasibility check, greedy and O(n). Greedy is optimal here because leaving space unused can never reduce the number of days.
  3. hi = midA feasible capacity is kept as a candidate, exactly like the lower-bound search — you are looking for the first True, not for any True.
  4. for cap in range(answer - 3, answer + 3)Printing the predicate either side of the boundary is how you check monotonicity rather than assuming it. A predicate that flips more than once cannot be binary searched.

Change one thing

  • Set lo = 1 instead of max(weights) and look at the answer. It is still correct here — work out why, and then find an input where it would not be.
  • Change the question to "the largest minimum gap when placing k items". The monotonicity reverses, so you search for the last feasible value instead of the first.

Where this runs

Real CPython, compiled to WebAssembly and running on your own machine — nothing is uploaded. The first run takes a few seconds while the interpreter downloads; after that it is immediate. Need more room, or want to paste your own attempt? Use the Python compiler.

Check yourself

0 of 4

Answer without scrolling back up.

  1. What is being binary searched?

  2. What property must the predicate have?

  3. What is the complexity?

  4. Why is lo initialised to max(weights)?

Cheat sheet

Binary search on the answer, not the array

Binary-search the answer space instead of an array. Solve the ship-capacity problem step by step and learn the template that fits dozens of variants.

INTERVIEW · vizlearn.in/interview/binary-search-on-the-answer.html

About the author

Ashish Jangra builds and maintains VizLearn. Every module here is written and the visualisation behind it hand-built, so the numbers in a readout come from the same code that draws the picture. Corrections are genuinely welcome and get priority over everything else — if a page states something wrong, or an animation misrepresents what the algorithm does, get in touch.