Try Every Speed
Time O(max(piles) * n)Space O(1)The brute-force way to find the minimum working speed is to try k = 1, 2, 3, ... in order and, for each one, compute how many hours it takes to clear every pile at that speed (ceil(pile / k) hours per pile). Stop at the first k that fits within h hours. Correct, but trying every candidate speed one at a time is wasteful.
import math
class Solution: def minEatingSpeed(self, piles: list[int], h: int) -> int: def hours_needed(k: int) -> int: return sum(math.ceil(p / k) for p in piles)
k = 1 while hours_needed(k) > h: k += 1 return kBinary Search on the Answer
OptimalTime O(n log(max(piles)))Space O(1)This is not a search over the input array β it is a search over the space of possible answers. The key structural fact: as the eating speed k increases, the number of hours needed is monotonically non-increasing. That monotonic relationship is exactly what binary search needs. So instead of scanning candidate speeds one by one, binary search directly on k, using hours_needed(k) <= h as the check: if the middle speed works, the answer is that speed or something smaller, so shrink the upper bound; otherwise it has to be bigger.
import math
class Solution: def minEatingSpeed(self, piles: list[int], h: int) -> int: def hours_needed(k: int) -> int: return sum(math.ceil(p / k) for p in piles)
lo, hi = 1, max(piles) while lo < hi: mid = (lo + hi) // 2 if hours_needed(mid) <= h: hi = mid else: lo = mid + 1 return loTracing piles = [3,6,7,11], h = 8 β the array below represents the candidate speeds 1 through 11, not the piles:
At speed 6, Koko needs 6 hours, which fits in 8. Speed 6 works, so the answer is at most 6 -- discard every speed above it and set hi = mid.
Why itβs correct: hours_needed(k) is a non-increasing function of k, so the set of speeds that satisfy hours_needed(k) <= h is a contiguous suffix of [1, max(piles)]. Binary search finds the left boundary of that suffix, which is the minimum valid speed. Complexity: each hours_needed check costs O(n), and the search space [1, max(piles)] halves every step, giving O(log(max(piles))) iterations, for O(n log(max(piles))) time, O(1) space.