875. Koko Eating Bananas
Quick Identifier
- Topic: binary-search
- Pattern: Binary Search (Search on answer)
- Difficulty: Medium
- Companies: Amazon, Google, Meta, DoorDash, Roblox
- Frequency: High
- LeetCode: 875
Quick Sights
- Time Complexity:
O(n log max)from the optimal approach. - Space Complexity:
O(1)from the optimal approach. - Core Mechanism: Given pile sizes and a limit on hours
hours, choose an integer eating speed (bananas per hour) so that all piles are finished withinhours; each pile takesceil(pile / speed)hours. Return the minimum feasible speed.
Concept Explanation
Given pile sizes and a limit on hours hours, choose an integer eating speed (bananas per hour) so that all piles are finished within hours; each pile takes ceil(pile / speed) hours. Return the minimum feasible speed.
The key is to state the invariant before coding: what part of the input is already settled, what state is still unresolved, and what single operation makes progress without losing correctness.
Recognition cues:
- “Minimum maximum” or “smallest X such that predicate holds”
- Monotonicity: if speed
speedworks, anyspeed+1also works ceilsum of per-pile times
Study Pattern (SDE3+)
- 0-3 min: restate I/O and brittle edges aloud, then verbalize two approaches with time/space before you touch the keyboard.
- Implementation pass: one-line invariant above the tight loop; state what progress you make each iteration.
- 5 min extension: pick one constraint twist (immutable input, stream, bounded memory, parallel readers) and explain what in your solution breaks without a refactor.
Diagram
This diagram shows the algorithm movement for this problem family.
Approaches
- Brute force —
O(max * n)time /O(1)space — try every speed from1tomax(piles). - Better — same monotonicity; still need to find transition point fast.
- Optimal —
O(n log max)time /O(1)space — binary search speed in[1, max]; check feasibility with sum of ceilings.
Optimal Solution
Go
func minEatingSpeed(piles []int, hours int) int {
maxBananas := 0
for _, pile := range piles {
if pile > maxBananas {
maxBananas = pile
}
}
left, right := 1, maxBananas
for left < right {
mid := left + (right-left)/2
if hoursNeeded(piles, mid) <= hours {
right = mid
} else {
left = mid + 1
}
}
return left
}
func hoursNeeded(piles []int, speed int) int {
total := 0
for _, pile := range piles {
total += (pile + speed - 1) / speed
}
return total
}JavaScript
function minEatingSpeed(piles, hours) {
let maxBananas = 0;
for (const pile of piles) {
maxBananas = Math.max(maxBananas, pile);
}
let left = 1;
let right = maxBananas;
while (left < right) {
const mid = left + Math.floor((right - left) / 2);
if (hoursNeeded(piles, mid) <= hours) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
function hoursNeeded(piles, speed) {
let total = 0;
for (const pile of piles) {
total += Math.ceil(pile / speed);
}
return total;
}Walkthrough
piles = [3,6,7,11], hours = 8
| speed | hours sum | ≤ 8? |
|---|---|---|
| 4 | 2+2+2+3=9 | no |
| 5 | 1+2+2+3=8 | yes |
Search finds minimum feasible in [1,11]. Invariant: feasible set is a suffix [answer, max].
Edge Cases
- One pile,
hoursequals pile size — answer can be1ifhoursallows. hours == len(piles)— must eat at leastmax(piles)per hour.- Large pile values — use 64-bit for hours sum in stricter versions.
Pitfalls
- Integer
ceilwithout floating math:(pile + speed - 1) / speed. - High bound too low — must be at least
max(piles)whenhours == len(piles).
Similar Problems
- 1011. Capacity to Ship Packages Within D Days — same “binary search on answer” with different feasibility check.
- 704. Binary Search — core halving mechanics.
- 35. Search Insert Position — first-true monotonic predicate pattern.
Variants
- Split array largest sum — same BS-on-answer skeleton with partition cost.
- Weighted hours per pile — adjust feasibility function only.
Mind-Map Tags
#binary-search #search-on-answer #monotone-feasible #ceil-sum
Mark this page when you finish learning it.
Last updated on
Spotted something unclear or wrong on this page?