piles hours each pile takes at speed k: ⌈p / k⌉
Speeds k = 1 … max(piles) the answer space; [l, r] is still in play
public int minEatingSpeed(int[] piles, int h) { int l = 1; int r = Arrays.stream(piles).max().getAsInt(); int res = r; // max(piles) always works while (l <= r) { int k = l + (r - l) / 2; long hours = 0; for (int p : piles) { hours += (p + k - 1) / k; } if (hours <= h) { res = k; // k works; try slower r = k - 1; } else { l = k + 1; // too slow; go faster } } return res;}
- l
- —
- r
- —
- k
- —
- hours
- —
- res
- —
Why it works
- Brute force tries every speed from 1 up and stops at the first that fits in
hhours. Each try costs O(n), and there can bemax(piles)tries: O(n·m). - The answer space is sorted by feasibility. If speed
kfinishes in time, any faster speed does too. So the speeds read "too slow, too slow, …, fits, fits": binary search for the first "fits". Invariant: the answer isresor lies inside[l, r]. - O(n log m) time. Each probe halves the speed range, about log₂(m) probes, and each probe sums n pile hours. O(1) extra space.
- Pitfall: integer division. A pile of 7 at speed 4 takes 2 hours, not 1, but
7 / 4is1in Java, andMath.ceil(7 / 4)still is, because the division truncates first. Use(p + k - 1) / k, orMath.ceil((double) p / k). Keephoursalong: with 104 piles of 109 the total overflowsint. Startinglat 0 would divide by zero (ArithmeticException). - Same pattern: Capacity to Ship Packages Within D Days (1011) and Split Array Largest Sum (410). Binary search the answer whenever a yes/no check is monotonic in it.