Koko loves to eat bananas. There are n
piles of bananas, the ith
pile has piles[i]
bananas. The guards have gone and will come back in h
hours.
Koko can decide her bananas-per-hour eating speed of k
. Each hour, she chooses some pile of bananas and eats k
bananas from that pile. If the pile has less than k
bananas, she eats all of them instead and will not eat any more bananas during this hour.
Koko likes to eat slowly but still wants to finish eating all the bananas before the guards return.
Return the minimum integer k
such that she can eat all the bananas within h
hours.
Example 1:
Input: piles = [3,6,7,11], h = 8 Output: 4
Example 2:
Input: piles = [30,11,23,4,20], h = 5 Output: 30
Example 3:
Input: piles = [30,11,23,4,20], h = 6 Output: 23
Constraints:
1 <= piles.length <= 104
piles.length <= h <= 109
1 <= piles[i] <= 109
This problem asks to find the minimum eating speed Koko needs to consume all bananas in h
hours. A binary search approach is highly efficient due to the problem's inherent monotonicity: if Koko can eat all bananas at speed k
, she can also do so at any speed greater than k
.
Algorithm:
Binary Search Space: The minimum speed is 1 banana/hour, and the maximum is the largest pile size (since she might need to eat that many in one hour). We initialize left = 1
and right = max(piles)
.
Binary Search Iteration: We repeatedly halve the search space until left
and right
converge.
Midpoint Calculation: mid = (left + right) // 2
(integer division). This represents the current test speed.
Time Calculation: We iterate through piles
, calculating the time needed to eat each pile at speed mid
. We use (pile + mid - 1) // mid
to handle cases where a pile doesn't divide perfectly by mid
(ceiling division). The total time total_time
is the sum of these individual times.
Check Condition: If total_time <= h
, it means Koko can finish eating within the time limit at this speed. We update right = mid
to search for a potentially lower speed. Otherwise, if total_time > h
, we need a faster speed, so we update left = mid + 1
.
Result: The loop continues until left == right
, at which point left
(or right
) holds the minimum speed that satisfies the condition.
Time Complexity Analysis:
piles
.piles
once, which takes O(n) time, where n is the number of piles.Space Complexity Analysis:
The algorithm uses only a few variables to store the boundaries, mid-point, and total time. The space complexity is O(1), constant.
Code Examples (Python):
import bisect
class Solution:
def minEatingSpeed(self, piles: list[int], h: int) -> int:
def check(k: int) -> bool:
return sum((x + k - 1) // k for x in piles) <= h # Efficient ceiling division
# Use bisect_left for a more concise binary search
return 1 + bisect_left(range(1, max(piles) + 1), True, key=check)
#Alternative implementation without bisect:
class Solution:
def minEatingSpeed(self, piles: list[int], h: int) -> int:
left, right = 1, max(piles)
while left < right:
mid = (left + right) // 2
total_time = sum((p + mid - 1) // mid for p in piles) # Ceiling division
if total_time <= h:
right = mid # Try a lower speed
else:
left = mid + 1 # Need a higher speed
return left # left == right at this point
The bisect_left
approach is more concise but might be slightly less readable for those unfamiliar with the bisect
module. Both achieve the same time and space complexity. Other language examples would follow similar logic, adapting the syntax and potentially using built-in functions equivalent to bisect_left
.