Back to Binary Search
Q5Question 5 of 14

Koko Eating Bananas: Binary Search on the Answer With a Feasibility Check

Key Concepts
  • Binary-search the answer (the speed), not an array: the search space is 1 to max(piles)
  • Feasibility function computes hours needed at a given speed; feasibility is monotonic
  • Ceiling division without floating point: (pile + speed - 1) / speed
  • Lower-bound search pattern: on feasible, try smaller (high = mid); on infeasible, go faster (low = mid + 1)
  • Time is O(n * log(max pile)) where n is the number of piles
  • The pattern generalizes to any optimization problem with a monotonic feasibility condition

Definition

Binary-search the answer itself, using a yes-or-no feasibility check that is monotonic.
  • Binary search on the answer – instead of searching an array, search the space of possible answers (eating speeds) for the minimum that satisfies a condition.
  • Feasibility function – computes hours needed at a given speed; the condition is that the hours do not exceed the deadline.
  • Monotonicity – if speed K finishes in time, every speed greater than K also finishes; if K is too slow, every slower speed is also too slow.
  • Ceiling division – (pile + speed - 1) / speed avoids floating-point error and stays exact.
  • Complexity – O(n * log(max pile)) where n is the number of piles.

The National Bank of India must clear a backlog of transaction batches before a regulatory cutoff. It can set a processing rate: how many items per hour each worker handles. A higher rate clears the backlog faster but costs more compute. The manager binary-searches the rate: pick a middle rate, compute whether the backlog clears in time, and if it does, try lower to save resources; if not, raise the rate.

Understanding the Concepts

What is the Binary Search on the Answer technique?

When the answer lies in a numeric range and the feasibility condition is monotonic (all speeds above a threshold pass, all below it fail), you binary-search the range for the boundary. This is the canonical technique tested with Koko Eating Bananas.

JAVA
package com.bank.service;

public class KokoEatingBananas {
    public static int minEatingSpeed(int[] piles, int h) {
        int low = 1;
        int 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;       // feasible: try slower
            } else {
                low = mid + 1;    // infeasible: must go faster
            }
        }
        return low;
    }

    private static boolean canFinish(int[] piles, int speed, int h) {
        long hours = 0;
        for (int pile : piles) {
            hours += (pile + speed - 1) / speed; // ceiling division
        }
        return hours <= h;
    }

    public static void main(String[] args) {
        int[] batches = {3000, 6000, 7000, 11000};
        int deadline = 8;
        System.out.println("Min processing rate: " + minEatingSpeed(batches, deadline));
    }
}
TEXT
Min processing rate: 4000

Feasibility is monotonic: if speed K finishes in time, every speed greater than K also finishes because each pile takes fewer or equal hours at a higher speed. If K is too slow, every speed less than K is also too slow. This clean yes-then-no boundary is exactly what binary search locates.

JAVA
// Monotonicity:
// speed=1000: needs 27 hours > 8 -> infeasible
// speed=3000: needs 10 hours > 8 -> infeasible
// speed=4000: needs  8 hours <= 8 -> FEASIBLE (boundary)
// speed=5000: needs  7 hours <= 8 -> feasible
// speed=6000: needs  6 hours <= 8 -> feasible
// Binary search finds the boundary (4000) in O(log(max_pile)) steps

Why use ceiling division instead of floating point?

A partial pile still costs a full hour. Ceiling division computes this exactly with integers. Floating-point division risks rounding errors that could miscount hours.

JAVA
// Ceiling division formula: (a + b - 1) / b
// Example: pile=7000, speed=3000
// (7000 + 3000 - 1) / 3000 = 9999 / 3000 = 3 (integer division)
// Correct: 7000/3000 = 2.33... rounds up to 3 hours

// WRONG: using floating point
// Math.ceil(7000.0 / 3000.0) = 3.0
// This works here but can fail on edge cases due to precision

// CORRECT: integer ceiling division
hours += (pile + speed - 1) / speed;

How does the lower-bound search pattern work?

The search uses the lower-bound pattern: when the mid speed is feasible, you try slower by setting high = mid (not mid - 1, because mid itself might be the answer). When infeasible, you must go faster by setting low = mid + 1. The loop runs while low < high, and when they converge, low is the minimum feasible speed.

JAVA
// Lower-bound binary search template:
while (low < high) {
    int mid = low + (high - low) / 2;
    if (condition(mid)) high = mid;   // mid might be the answer
    else low = mid + 1;              // mid is definitely not the answer
}
// low == high == answer

What are the bounds of the search space?

The minimum useful speed is 1 (eating at least one banana per hour). The maximum useful speed is the size of the largest pile, because eating faster than the largest pile gives no further benefit: each pile already takes one hour at most.

JAVA
int low = 1;
int high = 0;
for (int pile : piles) high = Math.max(high, pile);
// Searching [1, max(piles)] covers all meaningful speeds

What are the edge cases?

If there is one pile and one hour, the speed must be at least that pile's size. If h equals the number of piles, each pile must be eaten in one hour, so the speed is the largest pile. If h is very large, the speed approaches 1.

JAVA
package com.bank.service;

public class KokoEdgeCases {
    public static void main(String[] args) {
        // One pile, one hour
        System.out.println(KokoEatingBananas.minEatingSpeed(new int[]{5000}, 1)); // 5000
        // h = number of piles
        System.out.println(KokoEatingBananas.minEatingSpeed(new int[]{3, 6, 7, 11}, 4)); // 11
        // Large h
        System.out.println(KokoEatingBananas.minEatingSpeed(new int[]{3, 6, 7, 11}, 100)); // 1
    }
}
TEXT
5000
11
1

What are common mistakes?

The most common mistake is using high = mid - 1 instead of high = mid. Since mid itself might be the answer (the minimum feasible speed), setting high = mid - 1 can skip it.

JAVA
// WRONG:
if (canFinish(piles, mid, h)) high = mid - 1;  // might skip the answer

// CORRECT:
if (canFinish(piles, mid, h)) high = mid;  // mid might be the answer

Another mistake is using int instead of long for the hours sum, which overflows for large inputs.

How does this pattern generalize?

  • Binary search on the answer applies to any optimization problem where you can phrase the condition as a monotonic yes-or-no test. Examples include:
  • Ship packages within D days (search the ship capacity)
  • Split array into M subarrays minimizing the largest sum (search the sum threshold)
  • Aggressive cows: maximize minimum distance (search the distance)
JAVA
// General template:
int low = minPossibleAnswer, high = maxPossibleAnswer;
while (low < high) {
    int mid = low + (high - low) / 2;
    if (isFeasible(mid)) high = mid;   // minimizing: try smaller
    else low = mid + 1;
}
return low;

When should you use this technique?

Use binary search on the answer whenever the problem asks for a minimum or maximum value subject to a constraint, and you can verify any candidate in O(n) time. The total time becomes O(n * log(search range)).

In banking, this applies to finding the minimum processing rate to clear batch backlogs, the minimum server capacity to handle peak load, or the minimum interest rate to cover costs.

JAVA
package com.bank.service;

public class MinProcessingRate {
    public static void main(String[] args) {
        int[] batchSizes = {1500, 3200, 2800, 4100, 1900};
        int deadlineHours = 6;
        int minRate = KokoEatingBananas.minEatingSpeed(batchSizes, deadlineHours);
        System.out.println("Min rate to clear all batches in " + deadlineHours + " hours: " + minRate);
    }
}
TEXT
Min rate to clear all batches in 6 hours: 2800

What should a senior engineer know?

A senior engineer should explain the monotonicity proof and the ceiling-division trick. The real value of this problem is the template: any optimization with a monotonic feasibility check can be solved with binary search on the answer. Recognizing this pattern across different problem skins is what matters.

What are common interview follow-up questions?

  • Interviewers commonly ask:
  • Why ceiling division? (A partial pile costs a full hour; floating point risks rounding error.)
  • Why high = mid, not mid - 1? (Mid might be the answer.)
  • Time complexity? (O(n * log(max_pile)) where n is the number of piles.)
  • What other problems use this pattern? (Ship packages, split array, aggressive cows.)

Visual Overview

DIAGRAM
  Binary search on the answer:

  Piles: [3000, 6000, 7000, 11000], deadline = 8 hours
  Search space: [1, 11000]

  ┌─────────────────────────────────────┐
  │  low=1          mid=5500    high=11000 │
  │  canFinish(5500,8)?                    │
  │  hours = 1+2+2+2 = 7 <= 8 → yes       │
  │  high = 5500                           │
  │                                        │
  │  low=1          mid=2750    high=5500  │
  │  canFinish(2750,8)?                    │
  │  hours = 2+3+3+4 = 12 > 8 → no        │
  │  low = 2751                            │
  │                                        │
  │  ...converges...                       │
  │                                        │
  │  low=4000      high=4000               │
  │  Answer: 4000                          │
  └────────────────────────────────────────┘

  Feasibility is monotonic:
  speed:  1000  2000  3000  4000  5000 ...
  hours:    27    14    10     8     7 ...
  feasible:  N     N     N     Y     Y ...
             ──── boundary ────↑

Key Takeaway

Koko Eating Bananas is the textbook example of binary search on the answer, a technique where you search the space of possible answers rather than an array. The feasibility function computes how many hours Koko needs at a given speed by summing ceiling divisions. Feasibility is monotonic: faster speeds never need more hours, so a clean yes-or-no boundary exists for binary search to find.

The lower-bound search pattern converges on the minimum feasible speed: when feasible, try slower (high = mid); when infeasible, go faster (low = mid + 1). Ceiling division with integers, (pile + speed - 1) / speed, avoids floating-point rounding errors that could miscount hours before a compliance deadline.

The real value of mastering this problem is the template. Any optimization problem where a monotonic yes-or-no condition partitions the search space can be solved with binary search on the answer: ship packages within D days (search capacity), split array minimizing the largest sum (search the threshold), or aggressive cows (search the minimum distance).

In the batch clearing system at the National Bank of India, the batches are the piles, the regulatory cutoff is the hour budget, and the processing rate is the eating speed. Finding the minimum feasible rate directly saves compute costs. The ceiling-division trick keeps the calculation exact, and the O(n * log(max_pile)) time handles large batch pools within the scheduling window.

Remember one sentence: binary-search the candidate speed, check feasibility with ceiling division, and the monotonic boundary gives the minimum rate that clears everything in time.

---

Share
Use ← → arrow keys to navigate