875. Koko Eating Bananas

Problem Statement

Koko loves to eat bananas. There are n piles of bananas, the i<sup>th</sup> 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. (link)

Constraints:

  • 1 <= piles.length <= 10<sup>4</sup>

  • piles.length <= h <= 10<sup>9</sup>

  • 1 <= piles[i] <= 10<sup>9</sup>

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

Solution

Take the example of piles = [30,11,23,4,20]

The maximum bananas that can be eaten in an hour will be infinite or INT_MAX bananas. If we take INT_MAX also still the time taken will be 5 hours. If we go one step deep into the array the maximum value 30 present in the array also takes 5 hours. The value 30 gives koko peacfully eat in the full one hour. If it is INT_MAX then it will finish the pile in fraction of seconds and sit ideal for the rest of the hour.

Hence our answer can take atmost the maximum value present in the array or less than it. Therefore answer will be in the range of 1 and array max value.

Brute Force Approach

In this approach we will start with 1 and go till max value. For each rate we check whether koko can finish all the bananas within the given time period (h). We directly return the least value for which this condition is satisfied.

class Solution {
    public int minEatingSpeed(int[] piles, int h) {
        int maxValue = Arrays.stream(piles).max().getAsInt();
        for(int k=1; k<=maxValue; k++){
            int timeTaken = timeTakenToFinish(piles,k);
            if(timeTaken<=h){
                return k;
            }
        } 
        return -1;
    }

    public int timeTakenToFinish(int[] piles, int k){
        int totalTime = 0;
        for(int pile: piles){
            totalTime += Math.ceil((double)pile/k);
        }
        return totalTime;
    }
}

As our response will fall within the range of 1 to the maximum value, we will employ a binary search approach. It is established that to the right of the answer, every scenario will adhere to the condition, indicating that all piles will be completed within the specified time frame. Conversely, the condition fails to the left of the answer.

The lower bound starts at 1, and the upper bound starts at the maximum value. We examine whether the midpoint satisfies the condition; if it does, we shift towards the left; otherwise, we move towards the right of the midpoint. The minimum midpoint value that satisfies the condition can be stored in a global variable, "answer," or we can directly return the value of the lower pointer since, before the upper pointer surpasses the lower one, the midpoint/answer value will coincide with the lower value.

class Solution {
    public int minEatingSpeed(int[] piles, int h) {

        int maxValue = Arrays.stream(piles).max().getAsInt();

        int low = 1;
        int high = maxValue;

        while(low<=high){
            int mid = (low+high)>>1;
            int timeTaken = timeTakenToFinish(piles,mid);

            if(timeTaken<=h){
                high = mid-1;
            }else{
                low = mid+1;
            }
        }
        return low;
    }

    public int timeTakenToFinish(int[] piles, int k){
        int totalTime = 0;
        for(int pile: piles){
            totalTime += Math.ceil((double)pile/k);
        }
        return totalTime;
    }
}