🧠
Binary Search on Answer Space
💡 This approach uses binary search on the range of possible speeds to efficiently find the minimum speed. It leverages the monotonicity of the feasibility function, which is a key insight for this problem.
Intuition
The minimum speed lies between 1 and max pile size. We use binary search to guess a speed and check if Koko can finish in h hours. If yes, try smaller speeds; if no, try larger speeds.
Algorithm
- Set low = 1 and high = max pile size.
- While low < high:
- mid = (low + high) // 2
- If Koko can finish all piles at speed mid within h hours, set high = mid.
- Else, set low = mid + 1.
- Return low as the minimum speed.
💡 The key is defining the feasibility function and using binary search to narrow down the minimum speed efficiently.
from math import ceil
def can_finish(piles, speed, h):
hours = 0
for pile in piles:
hours += ceil(pile / speed)
return hours <= h
def minEatingSpeed(piles, h):
low, high = 1, max(piles)
while low < high:
mid = (low + high) // 2
if can_finish(piles, mid, h):
high = mid
else:
low = mid + 1
return low
# Driver code
if __name__ == '__main__':
piles = [3,6,7,11]
h = 8
print(minEatingSpeed(piles, h)) # Output: 4
Line Notes
def can_finish(piles, speed, h):Defines feasibility function to check if speed is sufficient.
hours += ceil(pile / speed)Calculate hours needed for each pile at given speed.
while low < high:Binary search loop to narrow down minimum speed.
if can_finish(piles, mid, h):If feasible, try smaller speeds by moving high down.
import java.util.*;
public class KokoEatingBananas {
private static boolean canFinish(int[] piles, int speed, int h) {
int hours = 0;
for (int pile : piles) {
hours += (pile + speed - 1) / speed;
}
return hours <= h;
}
public static int minEatingSpeed(int[] piles, int h) {
int low = 1, high = 0;
for (int pile : piles) high = Math.max(high, pile);
while (low < high) {
int mid = low + (high - low) / 2;
if (canFinish(piles, mid, h)) {
high = mid;
} else {
low = mid + 1;
}
}
return low;
}
public static void main(String[] args) {
int[] piles = {3,6,7,11};
int h = 8;
System.out.println(minEatingSpeed(piles, h)); // Output: 4
}
}
Line Notes
private static boolean canFinish(int[] piles, int speed, int h)Feasibility function to check if speed suffices.
hours += (pile + speed - 1) / speed;Calculate hours needed for each pile with ceiling division.
while (low < high)Binary search loop to find minimum speed.
if (canFinish(piles, mid, h))If feasible, try smaller speeds by adjusting high.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
bool canFinish(const vector<int>& piles, int speed, int h) {
long long hours = 0;
for (int pile : piles) {
hours += (pile + speed - 1) / speed;
}
return hours <= h;
}
int minEatingSpeed(vector<int>& piles, int h) {
int low = 1, high = *max_element(piles.begin(), piles.end());
while (low < high) {
int mid = low + (high - low) / 2;
if (canFinish(piles, mid, h)) {
high = mid;
} else {
low = mid + 1;
}
}
return low;
}
int main() {
vector<int> piles = {3,6,7,11};
int h = 8;
cout << minEatingSpeed(piles, h) << endl; // Output: 4
return 0;
}
Line Notes
bool canFinish(const vector<int>& piles, int speed, int h)Feasibility function to check if speed suffices.
hours += (pile + speed - 1) / speed;Calculate hours needed for each pile with ceiling division.
while (low < high)Binary search loop to find minimum speed.
if (canFinish(piles, mid, h))If feasible, try smaller speeds by adjusting high.
function canFinish(piles, speed, h) {
let hours = 0;
for (const pile of piles) {
hours += Math.ceil(pile / speed);
}
return hours <= h;
}
function minEatingSpeed(piles, h) {
let low = 1, high = Math.max(...piles);
while (low < high) {
const mid = Math.floor((low + high) / 2);
if (canFinish(piles, mid, h)) {
high = mid;
} else {
low = mid + 1;
}
}
return low;
}
// Driver code
const piles = [3,6,7,11];
const h = 8;
console.log(minEatingSpeed(piles, h)); // Output: 4
Line Notes
function canFinish(piles, speed, h)Feasibility function to check if speed suffices.
hours += Math.ceil(pile / speed);Calculate hours needed for each pile at given speed.
while (low < high)Binary search loop to find minimum speed.
if (canFinish(piles, mid, h))If feasible, try smaller speeds by adjusting high.
Binary search runs in log(max pile size) steps, and each step checks all piles (n). This is efficient for large inputs.
💡 If n=10^5 and max pile size=10^9, this means about 30 * 10^5 = 3 million operations, which is feasible.
Interview Verdict: Accepted
This is the optimal and accepted approach for this problem in interviews.