I’m trying to master the pattern known as Binary Search on the Answer Space. In problems like Koko Eating Bananas (or Ship Packages within D Days), we search for a minimum speed k that satisfies a time limit h.
However, when calculating ceiling hours like ceil(pile / k), many developers run into subtle floating-point precision issues or off-by-one boundary bugs where low and high get stuck in infinite loops. What is the bulletproof mathematical pattern to solve this cleanly?
In C++, when solving Koko Eating Bananas (or Ship Packages within D Days), you must avoid floating-point math and use
int64_tfor accumulating hours to prevent integer overflow bugs.Complexity: Runs in
O(N log(max_pile))time withO(1)space. Zero floating-point roundoff issues.Binary Search on Answer Space is one of the highest-leverage algorithmic patterns you can learn. Once you recognize it, dozens of seemingly hard problems (shipping packages, splitting arrays, cutting ribbons, allocating memory) all collapse into the exact same 15 lines of code.
1. When Can You Use This Pattern?
Ask yourself one simple question: Is the condition monotonic?
k = 100bananas/hour and succeeds in finishing in underhhours, would eating at speedk = 101also succeed? Yes, always.k = 5is too slow and fails, would eating at speedk = 4also fail? Yes, always.Because the outcome transitions cleanly from
False, False, ..., True, True, True, the answer space is monotonic. That means we don’t need to test every speed from 1 to 1 billion linearly—we can binary search it inO(log(MaxPile))steps!2. The Integer Ceiling Trick (Say Goodbye to Float Bugs)
If Koko has a pile of
7bananas and eats at speedk = 3, she needsceil(7 / 3) = 3hours.In Python or C++, doing
math.ceil(pile / k)converts the numbers to IEEE-754 64-bit floats. On massive numbers (e.g.10^14), floating-point precision degrades, causing silent off-by-one errors.The standard integer arithmetic replacement for
ceil(a / b)is:Let’s test it:
(7 + 3 - 1) // 3 = 9 // 3 = 3. Exactly right, 100% integer math, zero float conversions!3. Clean Python 3.12 Implementation
4. Complexity & Production Benchmarks
O(N * log(M))whereNis the number of piles andMismax(piles). IfM = 10^9,log2(10^9) ≈ 30. Even with 100,000 piles, the validation function runs at most 30 times. Total operations: ~3 million, executing in under 15 milliseconds.O(1)auxiliary memory.total_hourscan easily exceed2^31 - 1if speeds are small and piles are large. Always declareint64_t total_hours = 0;to prevent integer overflow.