Koko Eating Bananas
Problem statement
There are several piles of bananas, given as an array piles, and a deadline of h hours (h is at least the number of piles). An eater picks one fixed integer speed k bananas per hour. Each hour, they choose one pile and eat up to k bananas from it. If the pile has fewer than k left, they finish it and do nothing else for the rest of that hour.
Return the smallest speed k that lets them finish every pile within h hours.
Put another way: a pile of size p takes ceil(p / k) hours, and the sum of those hours must be at most h.
Examples
Example 1
Input: piles = [4, 9, 13], h = 6
Output: 5
Explanation: At speed 5 the piles take 1 + 2 + 3 = 6 hours. At speed 4 they take 1 + 3 + 4 = 8 hours, which is too slow.
Example 2
Input: piles = [12, 7], h = 5
Output: 4
Explanation: Speed 4 needs 3 + 2 = 5 hours. Speed 3 needs 4 + 3 = 7.
Hints
Approach
Binary-search the answer instead of the array. Define fast_enough(k) as "total hours at speed k is at most h". It is false for small k and true from some point on, and we want the first true.
- Set
lo = 1andhi = max(piles).hiis always fast enough. - While
lo < hi:mid = lo + (hi - lo) // 2;- if
fast_enough(mid), the answer ismidor smaller:hi = mid; - otherwise it is larger:
lo = mid + 1.
- Return
lo.
Each check costs O(n) and there are O(log M) checks.
O(n log M)Space O(1)class Solution: def minEatingSpeed(self, piles: list[int], h: int) -> int: def fast_enough(k: int) -> bool: return sum((p + k - 1) // k for p in piles) <= h lo, hi = 1, max(piles) while lo < hi: mid = lo + (hi - lo) // 2 if fast_enough(mid): hi = mid else: lo = mid + 1 return loFollow-up questions
- Each pile now has a different eating rate multiplier. Does binary search on the answer still work?
- Instead of one eater, there are
weaters working in parallel on separate piles. What changes in the check?
Frequently asked questions
It is capacity planning in disguise. Replace piles with queue backlogs and the speed with messages per worker per minute: what is the minimum throughput to drain every queue before a maintenance window closes? "Binary-search the smallest setting that passes a check" is a pattern you will reuse often.
Use (p + k - 1) // k. Floating-point division with math.ceil(p / k) works for small values but can round wrongly for very large integers, and it is slower.
With speed 1 and many large piles, the total hours can pass the int limit of about 2.1 billion and wrap to a negative number, which would make a too-slow speed look fast enough.