Understand
30-second explanation
Build the interview-ready mental model before comparing implementations.
There is no sorted array to search — instead binary search on the *answer*: the eating speed k. 'Can Koko finish within h hours at speed k?' is monotone — if a speed works, every larger speed works too. Binary search k in [1, max(piles)]; for each candidate, sum ⌈pile / k⌉ hours and keep the smallest k whose total ≤ h. O(n log(max(piles))) time, O(1) space.
Interview contextWhat is testedWhere candidates slipHow to stand outExplore interview contextHide interview context
What's being tested
Whether you recognise a 'minimize X subject to a monotone constraint' problem and binary search the answer space, rather than only knowing binary search as 'find element in sorted array'.
Where candidates slip
Computing hours with integer division (floor) instead of ceiling, setting the search range wrong (starting at 0, or hi too small), or overflowing the hour sum in Java.
How to stand out
State the monotonicity explicitly ('faster never hurts'), justify the [1, max] bounds, and use the smallest-feasible boundary template cleanly.
Choose
Compare the available approaches
Use constraints and trade-offs to select the route you can defend in an interview.
Interactive decision treeInteractiveChoose the right approachFirst decision previewCandidate speed k in [1, max(piles)]hours <= h?Yes (k works)No (too slow)Explore the full treeCollapse the tree
Learn & trace
Build each solution step by step
Move from the core idea to a visual trace, implementation, proof, and edge cases.
Approach 1 of 2
Linear Scan Over Speeds (Baseline)
1Hint 1Explore hintHide hint
What's the slowest speed that could possibly work, and the fastest you'd ever need?
2Hint 2Explore hintHide hint
Try k = 1, 2, 3, ... and for each compute the total hours; return the first k that fits in h.
3Hint 3Explore hintHide hint
Correct, but max(piles) can be 10⁹, so sweeping every speed is far too slow — notice the hours only ever decrease as k grows.
A · Core idea
Try every speed from 1 upward; for each, sum ⌈pile / k⌉ over all piles and return the first k whose total is ≤ h.
Why mention it. It surfaces the core sub-routine — the feasibility test hours(k) <= h — and makes the monotonic behaviour visible: as k increases, the total hours never increase. Why it's too slow. max(piles) reaches 10⁹, so a linear sweep is up to 10⁹ × 10⁴ operations. But the monotonicity we just noticed means we don't have to try every speed — we can binary search for the tipping point.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
piles = [3, 6, 7, 11], h = 8k=1
3+6+7+11 = 27 > 8
too slow4C · Code with teaching comments
Reference implementation previewpublic int minEatingSpeed(int[] piles, int h) { int max = 0; for (int p : piles) max = Math.max(max, p); for (int k = 1; k <= max; k++) { long hours = 0;Explore the full codeHide the full code
D · Why it works and complexityO(n * max(piles)) timeO(1) spaceOpen the invariant and proofExplore the proofHide the proof
The feasibility function hours(k) is monotonically non-increasing in k. Any monotone predicate over an ordered range is exactly the setting where linear scanning is wasteful and binary search shines.
ComplexityO(n * max(piles)) time, O(1) space — Up to max(piles) candidate speeds, each costing O(n) to total the hours.
E · Edge cases and pitfalls2Sweeping up to 10⁹ speeds — times out.Explore edge casesHide edge cases
Pitfalls
- Sweeping up to 10⁹ speeds — times out.
- Using floor division p // k instead of ceiling — undercounts hours for partial piles.
Approach 2 of 2 · Optimal
Binary Search on the Answer (Optimal)
1Hint 1Explore hintHide hint
You noticed hours(k) only goes down as k goes up. If speed k finishes in time, what do you know about every speed faster than k?
2Hint 2Explore hintHide hint
That monotonicity means the feasible speeds form a contiguous upper range. Binary search the boundary in [1, max(piles)].
3Hint 3Explore hintHide hint
For a candidate k, compute total hours = Σ⌈pile/k⌉. If ≤ h, the answer is k or smaller (hi = k); otherwise it's larger (lo = k + 1). Return lo.
A · Core idea
Binary search the speed rather than any array.
Reframing the problem. There's no sorted array to search here. What's ordered is the answer space: possible speeds 1, 2, …, max(piles). The function hours(k) = Σ ⌈piles[i] / k⌉ is monotonically non-increasing in k — eating faster never makes Koko take longer. Therefore the speeds that satisfy hours(k) <= h form a contiguous suffix [k*, max], and we want the leftmost feasible speed k*. That's a textbook boundary-finding binary search.
The bounds. The slowest meaningful speed is 1 (she must eat). The fastest useful speed is max(piles): at that speed every pile takes exactly one hour, and going faster can't reduce the per-pile cost below one hour, so it never helps. A feasible answer always exists because h >= piles.length, so k = max(piles) (one pile per hour) is guaranteed to fit.
The feasibility check. For a candidate k, sum ⌈piles[i] / k⌉. Use the integer-only ceiling (p + k - 1) / k to avoid floating-point error. In Java accumulate into a long: with up to 10⁴ piles each costing up to 10⁹ hours, an int sum overflows.
The boundary template. Use while (lo < hi) with lo = 1, hi = max(piles). Compute k = lo + (hi - lo) / 2. If hours(k) <= h, this speed works, but a slower one might too, so keep k as a candidate with hi = k. Otherwise k is too slow, so lo = k + 1. When lo == hi they point at the smallest feasible speed — return lo. Keeping mid on success (hi = k, not k - 1) is what makes this find the minimum.
Why this is fast. We replaced the linear sweep over up to 10⁹ speeds with log₂(10⁹) ≈ 30 feasibility checks. Each check is O(n), so the whole thing is O(n log(max(piles))) — instant even at the constraint limits.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
piles = [3, 6, 7, 11], h = 8Array state
lo=1, hi=11
k=6 → 6 hrs ≤ 8 feasible → search slower
4C · Code with teaching comments
D · Why it works and complexityO(n log(max(piles))) timeO(1) spaceOpen the invariant and proofExplore the proofHide the proof
The mental move is 'binary search the answer, not the input'. Whenever a problem says minimize/maximize a number such that a check passes, test whether the check is monotone in that number; if it is, binary search the numeric range and let an O(n) feasibility function do the work. This exact pattern solves Capacity to Ship Packages Within D Days, Split Array Largest Sum, and Minimum Number of Days to Make Bouquets — only the feasibility function changes.
ComplexityO(n log(max(piles))) time, O(1) space — log₂(max(piles)) candidate speeds, each feasibility check scanning all n piles → O(n log(max(piles))). Only scalars stored → O(1) space.
E · Edge cases and pitfalls8piles = [1000000000], h = 2 — hi = 1e9; with one pile, k = ceil(1e9 / h) ≈ 5e8 — long arithmetic prevents overflow.Explore edge casesHide edge cases
Edge cases handled
piles = [1000000000], h = 2hi = 1e9; with one pile, k = ceil(1e9 / h) ≈ 5e8 — long arithmetic prevents overflow.piles = [312884470], h = 312884469h huge but just shy of letting k=1 finish in one pass; binary search still finds the minimal speed.piles = [5], h = 5k must clear 5 bananas in 5 hours → k = 1 (ceil(5/1)=5 ≤ 5).h == piles.lengthOnly one hour per pile → answer is max(piles); the search converges to hi.
Pitfalls
- int overflow on the hour sum in Java — use long.
- Starting lo at 0 — speed 0 means she never finishes (division by zero too).
- Floor instead of ceiling for per-pile hours.
- Using hi = k - 1 on success — overshoots and may skip the true minimum.
Practice
Try the solution yourself
Edit the optimal implementation, test another input, and observe the result.
Editable code previewpublic int minEatingSpeed(int[] piles, int h) { int lo = 1, hi = 0; for (int p : piles) hi = Math.max(hi, p); while (lo < hi) { int k = lo + (hi - lo) / 2;Explore the playgroundClose the playground
Avoid mistakes
Recognize the interview traps
Understand why common attempts fail before reviewing the corrected implementation.
1Floor instead of ceiling hours
A pile that isn't a clean multiple of k still consumes a full final hour. Floor division undercounts, so an infeasible speed looks feasible.
Explore the code comparisonHide the code comparison
Floor instead of ceiling hours
A pile that isn't a clean multiple of k still consumes a full final hour. Floor division undercounts, so an infeasible speed looks feasible.
Don't write this
hours = sum(p // k for p in piles) # floor — wrongWrite this instead
hours = sum((p + k - 1) // k for p in piles) # ceil2Integer overflow on the hour sum
With up to 10⁴ piles each needing up to 10⁹ hours at k=1, the running total exceeds Integer.MAX_VALUE and wraps negative, breaking the comparison.
Explore the code comparisonHide the code comparison
Integer overflow on the hour sum
With up to 10⁴ piles each needing up to 10⁹ hours at k=1, the running total exceeds Integer.MAX_VALUE and wraps negative, breaking the comparison.
Don't write this
int hours = 0;
for (int p : piles) hours += (p + k - 1) / k;Write this instead
long hours = 0;
for (int p : piles) hours += (p + k - 1) / k;Revise
Carry the pattern into the interview
Pattern to remember
Binary search on the answer (monotone feasibility)
Code pattern to memorize
lo, hi = 1, max(piles)
while lo < hi:
k = lo + (hi - lo) // 2
hours = sum((p + k - 1) // k for p in piles)
if hours <= h: hi = k # k works, try smaller
else: lo = k + 1 # too slow, need faster
return loRules to remember
- 1Search the answer space [1, max(piles)], not array indices — k can never exceed the biggest pile (more speed is wasted).
- 2Hours for one pile is the ceiling
⌈p / k⌉; compute as(p + k - 1) / kto avoid floating point. - 3Feasibility is monotone: if speed k finishes in time, so does any speed > k — that monotonicity is what makes binary search valid.
- 4Use the
while (lo < hi)+hi = ktemplate to find the smallest feasible speed; returnlo. - 5Use
longfor the hour sum in Java — n up to 10⁴ piles of up to 10⁹ each can overflowint.
Use this pattern when
- 'Find the minimum/maximum value X such that a feasibility check passes' with a monotone check
- The thing you're optimising isn't in the input array but in a numeric range you define
- Problems phrased as 'smallest capacity / speed / time / threshold that still works'
Choose another pattern when
- The feasibility predicate isn't monotone in the parameter → binary search on the answer doesn't apply
- The answer range is tiny → a direct linear scan over candidates is simpler
- You're searching for an element that's literally in a sorted array → that's ordinary binary search
Interview takeaway
When the answer is a number with a monotone 'does this work?' test, binary search the answer range instead of the data. Recognising that monotonicity — 'bigger always stays feasible' — is the whole unlock, and it generalises to Capacity to Ship Packages, Split Array Largest Sum, and Minimum Speed to Arrive on Time.
Continue
Transfer the pattern to another problem
Use a direct variation or pattern sibling to prove the idea is reusable.
Transferable patternBinary search on the answer with a monotone feasibility predicate. Recognise it when the prompt is 'minimize/maximize a number such that a check passes' and 'bigger always stays feasible'. Same family as Capacity to Ship Packages and Split Array Largest Sum.
Practice queueDirect variations and pattern siblings
Direct follow-ups
- Capacity To Ship Packages Within D DaysComing soonBinary search the ship capacity; feasibility = packing fits in D days.
- Split Array Largest SumComing soonBinary search the max subarray sum; feasibility = ≤ m splits.
- Minimum Number of Days to Make m BouquetsComing soonBinary search on the day; feasibility = enough adjacent bloomed flowers.
- Binary SearchThe plain array version of the same halving idea.