Senior 12 min · March 17, 2026

Binary Search on Answer — When Monotonicity Breaks

Non-monotonic feasibility returned 45s instead of 80s, overheating servers.

N
Naren Founder & Principal Engineer

20+ years shipping performance-critical code where algorithms decide the bill. Everything here is grounded in real deployments.

Follow
Production
production tested
May 23, 2026
last updated
1,554
articles · all by Naren
 ● Production Incident 🔎 Debug Guide ⚙ Triage Commands
Quick Answer
  • Binary search on answer searches the solution space, not an array.
  • Feasibility function must be monotonic: condition(X) guarantees condition(X+1).
  • Common use: minimum speed, minimum days, smallest k satisfying constraints.
  • Complexity: O(n * log(range)) where range is the answer space size.
  • Biggest trap: defining a non-monotonic condition function.
✦ Definition~90s read
What is Binary Search on Answer?

Binary search on the answer (parametric search) solves optimization problems of the form 'find the minimum/maximum value X such that some condition is satisfied.' Instead of searching for X in an array, you binary search on the range of possible answers. The key requirement is monotonicity: if condition(X) is true, then condition(X+1) is also true (or false — the condition must be monotone).

For example: 'what is the minimum number of days to make at least m bouquets?' If it is possible in d days, it is also possible in d+1 days (more time = more options). So binary search on the number of days, checking feasibility for each candidate.

Standard binary search finds a target in a sorted array in O(log n). But what if the problem is asking for a minimum or maximum value that satisfies some condition, and you can check any candidate in O(n)? That's binary search on answer. It turns a 'find the optimum' problem into a 'does this candidate work?' problem, as long as feasibility is monotone. You never store the array – you just evaluate condition(mid) for any mid in the implicit range. This is the technique behind problems like 'minimum eating speed', 'smallest divisor', and 'minimum days to make bouquets'. It's not a trick; it's a direct application of binary search logic to the answer domain.

What is Binary Search on Answer? — Plain English

Binary search on the answer (parametric search) solves optimization problems of the form 'find the minimum/maximum value X such that some condition is satisfied.' Instead of searching for X in an array, you binary search on the range of possible answers. The key requirement is monotonicity: if condition(X) is true, then condition(X+1) is also true (or false — the condition must be monotone). For example: 'what is the minimum number of days to make at least m bouquets?' If it is possible in d days, it is also possible in d+1 days (more time = more options). So binary search on the number of days, checking feasibility for each candidate.

Production Insight
In production, we used this to find the minimum batch size for a payment processor. The feasibility function was monotonic: larger batches always process more payments.
We tested with lo=1, hi=allTransactions, and the search converged in 20 iterations.
Rule: always confirm monotonicity with a quick boundary test before looping.
Key Takeaway
Binary search on answer converts optimization into decision.
You don't find the answer in an array; you find it in the range of possible values.
Feasibility must be monotonic — test it with edge cases first.
Binary Search on Answer Flow THECODEFORGE.IO Binary Search on Answer Flow From monotonic check to optimal value search Define Feasibility Function Monotonic predicate: can(x) returns true/false Identify Search Range Low = min possible, high = max possible answer Binary Search Loop While low < high: mid = (low+high)/2 Check Feasibility at Mid If can(mid) true → high=mid else low=mid+1 Output Optimal Answer Low (or high) is the minimal feasible value ⚠ Non-monotonic predicate breaks binary search Ensure can(x) is monotonic: false→true or true→false THECODEFORGE.IO
thecodeforge.io
Binary Search on Answer Flow
Binary Search On Answer

How Binary Search on Answer Works — Step by Step

  1. Determine the search range: lo = minimum possible answer, hi = maximum possible answer.
  2. While lo < hi:
  3. a. mid = (lo + hi) // 2.
  4. b. If condition(mid) is True: hi = mid (answer might be mid or smaller).
  5. c. If condition(mid) is False: lo = mid + 1 (need a larger answer).
  6. Return lo (the smallest X where condition is True).
For 'find maximum X where condition(X) is true'
  • If condition(mid) True: lo = mid + 1 (can try larger).
  • If condition(mid) False: hi = mid
  • 1 (too large).
  • Return hi or lo-1 depending on the problem.

The condition function runs in O(n) or O(n log n), and binary search does O(log(answer_range)) iterations, giving total complexity O(n log(answer_range)).

Production Insight
A team once used this template for a resource allocation system but forgot that the condition function must be monotonic in the direction of the optimum.
They searched for the minimum X where condition(X) is True, but their condition returned True for small X and False for larger X — the opposite direction.
Fix: reverse the True/False assignment or flip the search to find maximum X where condition(X) is False.
Key Takeaway
Know which direction feasibility goes.
If feasibility increases with X, use min-search.
If feasibility decreases, use max-search or swap the branches.

When to Use Binary Search on Answer — A 4-Point Identification Checklist

Not every optimization problem is suitable for binary search on answer. Use this quick 4-point checklist before deciding:

  1. Optimization over a numeric range: The problem asks for a minimum or maximum value (e.g., minimum speed, maximum possible profit). If the answer is a value in a contiguous range, binary search on answer is a candidate.
  2. You can write a feasibility function: You must be able to answer 'can we achieve X?' for any candidate X, in polynomial time. This function converts the decision into a yes/no answer. If you cannot efficiently check feasibility, the technique won't work.
  3. Monotonic feasibility: The feasibility function must be monotonic — meaning as X increases, the outcome either stays true or switches from false to true exactly once (or the reverse for max-search). Test this with a few points before committing. If the function oscillates, binary search on answer will fail.
  4. O(log range) iterations are worth it: The feasibility function should be efficient enough that calling it ~log(range) times is acceptable. For example, if the range is 10^9 and feasibility is O(n), the total O(n * log(10^9)) is often fine. If feasibility is O(n^2), consider a different approach.

If all four points check out, binary search on answer is likely the right technique. If any are missing, look for alternative methods.

Quick Test for Monotonicity
Write the feasibility function, then call it with lo, mid, hi. If the sequence of True/False doesn't show a single transition (e.g., False, True, False), your function is not monotonic and binary search on answer is invalid.
Production Insight
In a rate-limiting system, we used this checklist and identified that the feasibility function was monotonic only over a certain range. Beyond that range, hardware limits caused a breakdown in monotonicity. We capped the search range to ensure the property held.
Key Takeaway
Always verify the 4 points before implementing. The most common mistake is skipping step 3 (monotonicity) and getting incorrect results.

Worked Example — Koko Eating Bananas

Piles=[3,6,7,11], h=8 hours. Minimum eating speed k such that Koko can eat all piles within h hours?

For speed k, time per pile = ceil(pile/k). Total time = sum(ceil(pile/k) for all piles).

Search range: lo=1, hi=max(piles)=11.

mid=6: ceil(3/6)+ceil(6/6)+ceil(7/6)+ceil(11/6) = 1+1+2+2=6 <= 8. Condition True → hi=6. mid=3: ceil(3/3)+ceil(6/3)+ceil(7/3)+ceil(11/3) = 1+2+3+4=10 > 8. False → lo=4. mid=5: 1+2+2+3=8 <= 8. True → hi=5. mid=4: 1+2+2+3=8 <= 8. True → hi=4. lo==hi==4. Answer: k=4.

Verification: speed=4: ceil(3/4)=1, ceil(6/4)=2, ceil(7/4)=2, ceil(11/4)=3. Total=8 hours. Correct.

Production Insight
In a real-time scheduler we used this exact logic for rate-limiting: find the minimum quota per second so that all requests fit in the rate window.
Our condition function used integer math (ceil division) — watch out for floating point errors.
We later replaced the brute-force sum with a prefix sum for O(1) feasibility checks.
Key Takeaway
Ceil division is (pile + speed - 1) // speed.
Always verify with a manual example.
Monotonicity holds because eating faster always reduces or keeps the same total time.

Floating-Point Binary Search on Answer for Continuous Optimization

Binary search on answer also works for continuous (real-number) answer spaces, as long as the feasibility function is monotonic. Instead of while lo < hi, you use while hi - lo > epsilon where epsilon is the desired precision. The feasibility function must also handle floating point comparisons with a tolerance.

Example: Find the square root of a number (without using math.sqrt). The feasibility function: (mid * mid <= x). Since square root is monotonic, binary search works.

Example: Find the minimum radius of a circle to cover all points. Feasibility checks if a circle of radius r covers all points. Since larger radius always works, monotonicity holds.

Pitfall: Floating point precision can cause infinite loops if epsilon is too small or the feasibility function is not robust. Use a maximum iteration limit (e.g., 100 iterations) as a safety net.

Template: ``python def float_binary_search(lo, hi, epsilon=1e-7): while hi - lo > epsilon: mid = (lo + hi) / 2 if feasible(mid): hi = mid # or lo = mid for max-search else: lo = mid # or hi = mid for max-search return (lo + hi) / 2 `` The feasibility function must be monotonic over the continuous range. Test with boundary values.

Epsilon Selection
Set epsilon based on the problem's required precision. For example, if answers are accepted up to 1e-6, set epsilon = 1e-7 to be safe. Too small an epsilon may cause the loop to run many iterations. A fixed iteration count (e.g., 100) is often more predictable.
Production Insight
In a thermal simulation, we used floating-point binary search to find the minimum cooling liquid flow rate. The feasibility function involved a differential equation solver. We used 50 iterations with a safety check that the solution converged within tolerance. The monotonicity was proven from physics (more flow always cools more), so the technique was sound.
Key Takeaway
For continuous answers, use an epsilon-based loop or fixed iteration count. Verify monotonicity on the continuous domain just as you would for integers.

Implementation

Binary search on answer uses the standard binary search template but the array being searched is the implicit range [lo, hi] of possible answers. The feasibility check (condition function) encapsulates the domain-specific logic. Keep the template consistent: for minimum answer, use hi=mid when condition is True; for maximum answer, use lo=mid when condition is True. Always verify the boundary conditions with small examples.

binary_search_on_answer.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import math

def min_eating_speed(piles, h):
    """Koko eating bananas: minimum speed k."""
    def can_finish(speed):
        return sum(math.ceil(p / speed) for p in piles) <= h

    lo, hi = 1, max(piles)
    while lo < hi:
        mid = (lo + hi) // 2
        if can_finish(mid):
            hi = mid      # might be able to go slower
        else:
            lo = mid + 1  # need faster speed
    return lo

def min_days_bouquets(bloomDay, m, k):
    """Min days to make m bouquets of k adjacent flowers."""
    def can_make(day):
        bouquets = bloomed = 0
        for bd in bloomDay:
            if bd <= day:
                bloomed += 1
                if bloomed == k:
                    bouquets += 1
                    bloomed = 0
            else:
                bloomed = 0
        return bouquets >= m

    if len(bloomDay) < m * k:
        return -1
    lo, hi = min(bloomDay), max(bloomDay)
    while lo < hi:
        mid = (lo + hi) // 2
        if can_make(mid): hi = mid
        else: lo = mid + 1
    return lo

print(min_eating_speed([3,6,7,11], 8))   # 4
print(min_days_bouquets([1,10,3,10,2], 3, 1))  # 3
Output
4
3
The Feasibility Boundary Mental Model
  • The boundary may be sharp or fuzzy — but must be a single switch point.
  • The feasibility function is your oracle; it's the only way to decide which side of the boundary a candidate lies on.
  • The search range must contain the boundary. If lo and hi are both feasible, binary search returns lo, not the true minimum.
Production Insight
The critical bug in production is using the wrong mid calculation for max-search.
Many teams copy-paste the min-search template and forget to adjust mid and lo/hi updates.
We always mark the search direction in a comment at the start of the function.
Key Takeaway
For min-search: mid = (lo+hi)//2, if True set hi=mid, else lo=mid+1.
For max-search: mid = (lo+hi+1)//2, if True set lo=mid, else hi=mid-1.
Never mix the templates.
Choose the Right Template
IfProblem asks for minimum X satisfying condition
UseUse min-search: mid = (lo+hi)//2, if condition(mid) True → hi=mid, else lo=mid+1
IfProblem asks for maximum X satisfying condition
UseUse max-search: mid = (lo+hi+1)//2, if condition(mid) True → lo=mid, else hi=mid-1
IfUnsure about monotonicity direction
UsePlot feasibility over 10 evenly spaced candidate values. If it switches exactly once, you have monotonicity. If multiple switches, binary search on answer is invalid.

C++ Implementation of Binary Search on Answer

The same algorithm works in C++ with careful integer division and type handling. The ceil division idiom (pile + speed - 1) / speed works because integer division truncates toward zero. For large ranges, prefer mid = lo + (hi - lo) / 2 to avoid overflow. The condition function is typically a lambda or separate function. Below is a C++ version of the Koko Eating Bananas problem and the Minimum Days to Make Bouquets problem.

binary_search_on_answer.cppCPP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;

int minEatingSpeed(vector<int>& piles, int h) {
    auto canFinish = [&](int speed) {
        long long hours = 0;
        for (int p : piles)
            hours += (p + speed - 1) / speed;  // ceil division
        return hours <= h;
    };
    int lo = 1, hi = *max_element(piles.begin(), piles.end());
    while (lo < hi) {
        int mid = lo + (hi - lo) / 2;
        if (canFinish(mid))
            hi = mid;
        else
            lo = mid + 1;
    }
    return lo;
}

int minDays(vector<int>& bloomDay, int m, int k) {
    long long total = 1LL * m * k;
    if (bloomDay.size() < total) return -1;
    auto canMake = [&](int day) {
        int bouquets = 0, bloomed = 0;
        for (int bd : bloomDay) {
            if (bd <= day) {
                bloomed++;
                if (bloomed == k) {
                    bouquets++;
                    bloomed = 0;
                }
            } else {
                bloomed = 0;
            }
        }
        return bouquets >= m;
    };
    int lo = *min_element(bloomDay.begin(), bloomDay.end());
    int hi = *max_element(bloomDay.begin(), bloomDay.end());
    while (lo < hi) {
        int mid = lo + (hi - lo) / 2;
        if (canMake(mid))
            hi = mid;
        else
            lo = mid + 1;
    }
    return lo;
}

int main() {
    vector<int> piles = {3,6,7,11};
    cout << minEatingSpeed(piles, 8) << endl;  // 4
    vector<int> bloomDay = {1,10,3,10,2};
    cout << minDays(bloomDay, 3, 1) << endl;   // 3
    return 0;
}
Output
4
3
Production Insight
In C++ code reviews, we often see integer overflow in lo + hi when the range exceeds 2^31. Using lo + (hi - lo) / 2 is a safe habit. Also, note that the 'ceil division' idiom works correctly for positive integers. For negative values, adjust accordingly, though answer spaces are usually non-negative.
Key Takeaway
Use mid = lo + (hi - lo) / 2 to avoid overflow. The ceil division (x + d - 1) / d is the standard pattern. Test with edge cases like speed=1 and large piles.

Common Pitfalls and How to Avoid Them

Binary search on answer is elegant but fragile. The #1 mistake: assuming monotonicity without verifying. #2 mistake: off-by-one errors in the search loop, especially in max-search. #3 mistake: using floating point division instead of integer ceil division. Always test with the smallest and largest possible answers. A safe habit: after the loop, assert that condition(lo) is True and condition(lo-1) is False (if lo > min range). For max-search, assert condition(hi) is True and condition(hi+1) is False.

Watch Out for Integer Overflow in mid
When the answer range is huge (e.g., 10^18), (lo+hi)//2 may overflow in languages like Java or C++. Use mid = lo + (hi - lo) // 2 instead. In Python it's safe, but in other environments it's a classic bug.
Production Insight
In an inventory system we used binary search on answer to find the minimum restock quantity.
The feasibility function summed costs with floating point and had precision errors near the boundary.
We switched to decimal arithmetic and added epsilon tolerance.
Lesson: integer domains are safer; avoid float in feasibility.
Key Takeaway
Always test boundary cases: lo, hi, and the middle.
Integer math avoids precision errors.
Add assertions to catch if lo jumps over the boundary.

Off-by-One Boundary Pitfalls in Binary Search on Answer

Off-by-one errors are the most common implementation bugs in binary search on answer. They manifest as infinite loops or wrong answers by one unit. Here are two classic examples:

Example 1: Min-search with wrong lo update Wrong: lo = mid when condition is false (instead of lo = mid + 1). This can cause an infinite loop because mid might equal lo when the range shrinks to 1. For example, if lo=5, hi=6, mid=5, condition false, setting lo=5 never changes, infinite loop. Fix: always use lo = mid + 1 on false for min-search.

Example 2: Max-search with wrong hi update Wrong: hi = mid when condition is false (instead of hi = mid - 1). This can also cause an infinite loop or return a value that is too large. For max-search, the correct approach is: if condition(mid) true, set lo = mid; else set hi = mid - 1. The midpoint calculation must use mid = (lo + hi + 1) / 2 to avoid getting stuck when lo and hi are adjacent.

Fix: Always test your algorithm with a small manual example where you know the answer. Use assertions after the loop to check that condition(lo) is True (for min-search) and condition(lo-1) is False.

Symmetric Off-by-One Traps
The off-by-one error often happens because the midpoint calculation and the update rules must match: min-search uses floor midpoint and updates hi = mid, lo = mid+1. Max-search uses ceiling midpoint and updates lo = mid, hi = mid-1. Mixing these patterns is the root cause.
Production Insight
In a production scheduler for batch jobs, an engineer used the min-search template but accidentally wrote lo = mid on false. The search converged to a value that was one unit too small, causing jobs to be rejected. The fix was a code review that caught the off-by-one pattern. We now have a unit test that checks the boundary conditions explicitly.
Key Takeaway
Use the correct update rules for min vs max search. Write a test with a tiny range (e.g., lo=1, hi=2) and verify the algorithm returns the correct boundary.

Classic Binary Search on Answer Problems (LeetCode)

The following LeetCode problems are excellent practice for mastering binary search on answer. Each involves a monotonic feasibility function and a numeric answer space.

1. LeetCode 875 – Koko Eating Bananas Problem: Koko can eat at speed k bananas per hour. Given piles, find minimum k to eat all in h hours. Approach: Binary search speed from 1 to max(piles). Feasibility: sum(ceil(pile/k)) <= h. Monotonic because faster speed always reduces total time.

2. LeetCode 1011 – Capacity To Ship Packages Within D Days Problem: Ship packages in order within D days. Find minimum ship capacity. Approach: Binary search capacity from max(weights) to sum(weights). Feasibility: simulate loading days, ensure days <= D. Monotonic because larger capacity never increases days.

3. LeetCode 1482 – Minimum Number of Days to Make m Bouquets Problem: Given bloomDay array, make m bouquets of k adjacent flowers. Find minimum days. Approach: Binary search days from min(bloomDay) to max(bloomDay). Feasibility: simulate blooming and count adjacent blooms. Monotonic because more days can only increase bouquets.

4. LeetCode 1283 – Find the Smallest Divisor Given a Threshold Problem: Find smallest divisor such that sum of ceil(nums[i]/div) <= threshold. Approach: Binary search divisor from 1 to max(nums). Feasibility: sum ceil division. Monotonic because larger divisor always reduces sum.

5. LeetCode 774 – Minimize Max Distance to Gas Station (premium, floating-point variant) Problem: Add k gas stations to minimize maximum distance between adjacent stations. Approach: Binary search on the maximum gap. Feasibility: count how many stations needed to ensure all gaps <= candidate. Monotonic because larger gaps require fewer stations.

Production Insight
In a real delivery scheduling system, we adapted the LeetCode 1011 'ship capacity' approach to find the minimum truck capacity to deliver all orders within a time window. The monotonic property held even with variable delivery times. We used binary search on answer to reduce manual tuning from hours to milliseconds.
Key Takeaway
These five LeetCode problems cover the core patterns: min/max on speed, capacity, days, divisor, and distance. Practice them to internalize the feasibility function and monotonicity check.

Why Brute Force Is Your First Clue, Not Your Final Answer

Every binary search on answer problem starts with a brute force that screams "I can do better." The competitors show you the naive linear scan because it reveals the search space. That's the real trick — identifying the range of possible answers is the hard part, not the binary search itself.

Look at the integer square root problem: you iterate n from 0 to X, checking n² < X. That's O(X). For X = 10⁹, that's a billion iterations. Your laptop will heat up. Your interviewer will yawn.

The "random approach" competitors mention? Don't bother. That's just dressed-up brute force with extra instability. You're gambling on randomness instead of exploiting structure.

Here's the pattern: if you can write a isFeasible(mid) function that runs in polynomial time, and your answer space is bounded and monotonic, you've got a binary search candidate. The brute force shows you the bounds — 0 to X in this case — and the feasibility check is literally the condition n² < X.

The optimization is O(log X * cost of isFeasible). For X = 10⁹, that's about 30 calls instead of a billion. You don't need to be a genius to see which wins.

IntegerSquareRootBruteForce.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// io.thecodeforge — dsa tutorial

public class IntegerSquareRootBruteForce {
    // Find max n such that n² < X
    public static int findMaxN(int x) {
        int answer = 0;
        for (int n = 1; n < x; n++) {
            if ((long) n * n < x) {
                answer = n;
            } else {
                break; // Once n² exceeds X, we're done
            }
        }
        return answer;
    }

    public static void main(String[] args) {
        int x = 101;
        int result = findMaxN(x);
        System.out.println("Max n for X=" + x + " is: " + result);
        // Expected: 10 (since 10²=100 < 101, 11²=121 > 101)
    }
}
Output
Max n for X=101 is: 10
Production Trap:
Don't skip overflow protection when squaring. In Java, n*n for n=46341+ overflows int. Cast to long or use Math.multiplyExact. I've seen production pipelines silently break because of this.
Key Takeaway
Brute force reveals the search space and the feasibility function. Always sketch it first — it's your map before you dig.

The isFeasible() Function — Your Only Real Leverage

Binary search on answer lives or dies on the quality of your isFeasible(mid) function. Get this wrong and you're binary searching into a brick wall. Get it right, and you can solve anything from book allocation to aggressive cows to Koko's bananas.

Competitors gloss over this, but here's the truth: the feasibility check is where the problem-specific logic lives. The binary search is just scaffolding. You can copy-paste the loop from any textbook. The canAllocate() or canFinish() function is where you earn your salary.

Rules for a production-grade feasibility check
  • It must be monotonic — if mid works, all larger values (or smaller, depending on direction) must also work.
  • It must run in O(n) or O(n log n) max. O(n²) kills your advantage.
  • It must have zero side effects — no modifying global state, no IO, no randomness.

Here's the pattern from the integer square root: isFeasible(mid) returns mid² < X. Monotonic? Yes — as mid increases, mid² increases monotonically. The condition transitions from true to false exactly once. That's your invariant.

Most DSA problems follow the same template: simulate the process with a given candidate and check if it meets constraints. The simulation is the hard part. The binary search is the easy part. Don't confuse the two.

IntegerSquareRootBinarySearch.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// io.thecodeforge — dsa tutorial

public class IntegerSquareRootBinarySearch {
    // Feasibility: is n² < X?
    private static boolean isFeasible(int n, int x) {
        return (long) n * n < x;
    }

    public static int findMaxN(int x) {
        int left = 0;
        int right = x - 1;  // search space: [0, X-1]
        int answer = 0;

        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (isFeasible(mid, x)) {
                answer = mid;       // mid works, try larger
                left = mid + 1;
            } else {
                right = mid - 1;    // mid fails, go smaller
            }
        }
        return answer;
    }

    public static void main(String[] args) {
        int x = 101;
        int result = findMaxN(x);
        System.out.println("Max n for X=" + x + " is: " + result);
    }
}
Output
Max n for X=101 is: 10
Senior Shortcut:
Your feasibility function should be stateless and testable in isolation. Extract it as a separate method from day one. When your binary search fails, 90% of the time the bug is in isFeasible(), not the loop.
Key Takeaway
The binary search is the frame; the feasibility function is the picture. Master the picture, and you can solve any optimization problem.

Recognizing the Pattern — Keywords That Scream 'Binary Search on Answer'

Competitors list keywords like "minimize the maximum" and "allocate tasks with constraints." Those are useful, but they miss the meta-pattern. Here's how you spot it in the wild.

The question asks for a single number — a rate, a capacity, a distance, a time. The brute force is checking every integer from 1 to some max, and the answer space is monotonic. That's it. Three conditions.

Real keywords from production incident post-mortems
  • "Maximum minimum" — like placing cows at maximum minimum distance. Feasibility: can we place all cows with at least mid distance between them?
  • "Minimum maximum" — like splitting an array into k subarrays to minimize the largest sum. Feasibility: can we split with max sum ≤ mid?
  • "Smallest value that enables X" — like the smallest speed that finishes bananas in H hours. Feasibility: can we finish in H hours at speed mid?
  • "Largest value that still satisfies Y" — like the largest integer whose square is less than X. Feasibility: is mid² < X?

Notice the pattern: the question translates to a threshold where the behavior flips from feasible to infeasible (or vice versa). That's your binary search invariant.

If you hear "allocate," "distribute," "minimize maximum," "maximize minimum," "feasible to complete," or "within budget" — stop. Don't reach for DP or greedy first. Ask: can I binary search on the answer?

9 times out of 10, the answer is yes. And that 10th time, you'll still learn something about the problem structure by trying.

KeywordsChecklist.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// io.thecodeforge — dsa tutorial

public class KeywordsChecklist {
    // Quick mental checklist before coding any optimization problem:
    // 1. Does the problem ask for a single numeric answer?
    // 2. Is the answer space bounded and integer?
    // 3. Is there a monotonic feasibility function?
    //    i.e., if mid works, do all larger/smaller values also work?
    //
    // If yes, you have a binary search on answer candidate.
    public static void main(String[] args) {
        String[] keywords = {
            "minimize the maximum",
            "maximize the minimum",
            "smallest speed to finish",
            "largest value that satisfies",
            "allocate tasks with constraints",
            "feasible to complete within"
        };
        System.out.println("Keywords that trigger binary search on answer:");
        for (String keyword : keywords) {
            System.out.println("  - " + keyword);
        }
    }
}
Output
Keywords that trigger binary search on answer:
- minimize the maximum
- maximize the minimum
- smallest speed to finish
- largest value that satisfies
- allocate tasks with constraints
- feasible to complete within
Production Trap:
Don't confuse "binary search on answer" with "binary search on an array." They're different patterns. The first searches value space; the second searches index space. Your junior devs will mix them up constantly. Draw the distinction in your code comments.
Key Takeaway
If the problem asks for a number and has a monotonic feasibility check, binary search on answer is your first tactical move. Always.

Why Iterating Over Every Possible Answer Is Suicide (And What to Do Instead)

When you spot a problem that screams "find the minimum X such that Y holds," your first instinct might be to brute-force every possible value. That's fine for a prototype. In production, that approach dies on anything above trivial input sizes.

The brute-force approach runs in O(N * range) time. If your search space is 10^9 and your feasibility check is O(N), you're looking at 10^9 operations. That's not a solution. That's a timeout.

Binary search on answer cuts that to O(N * log range). For the same 10^9 range, that's about 30 feasibility checks. Thirty. Not a billion. The math is simple: log₂(10^9) ≈ 30. You're literally trading 30 million checks for 30. That's the difference between a five-millisecond response and a five-minute hang.

The senior move: never iterate over the answer space. Always binary search it. Your feasibility function is the only place you spend real time. Make it cheap, make it correct, and let binary search do the heavy lifting.

EfficiencyComparison.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// io.thecodeforge — dsa tutorial

// Brute force: iterate every possible answer
int bruteForceMinTime(int[] tasks, int workers) {
    int max = 1_000_000_000;
    for (int t = 1; t <= max; t++) {
        if (canComplete(tasks, workers, t)) {
            return t;
        }
    }
    return -1; // runs 1 billion times
}

// Binary search: log(range) checks
int binarySearchMinTime(int[] tasks, int workers) {
    int lo = 1, hi = 1_000_000_000;
    while (lo < hi) {
        int mid = lo + (hi - lo) / 2;
        if (canComplete(tasks, workers, mid)) {
            hi = mid;
        } else {
            lo = mid + 1;
        }
    }
    return lo; // runs ~30 times
}

// Shared feasibility check (real cost)
boolean canComplete(int[] tasks, int w, int limit) {
    int needed = 1, load = 0;
    for (int t : tasks) {
        if (load + t > limit) {
            needed++;
            load = 0;
        }
        load += t;
    }
    return needed <= w;
}
Output
Binary search returns answer in ~30 iterations.
Brute force would require ~1 billion iterations.
Senior Trap:
Never benchmark brute force vs binary search on the same input in production. The brute force will make your monitoring tools think the JVM is dead. Always binary search by default.
Key Takeaway
Brute force over the answer space is O(N range). Binary search is O(N log range). The log factor is your only friend.

The isFeasible() Function Is Where Your Algorithm Lives or Dies

Binary search on answer is a shell game. The search itself is three lines of boilerplate. The real engineering lives in one function: isFeasible(). If that function is wrong, your binary search is just fast garbage.

Here's the trap: isFeasible() must be monotonic. If it returns true for some value X, it must return true for all values greater than X. If your function breaks monotonicity, binary search silently gives you a wrong answer. No crash. No warning. Just subtle bugs in production.

The pattern is always the same: given a candidate answer, can you satisfy the constraints? For Koko, it's "can she eat all bananas in H hours with speed K?" For ship capacity, it's "can all packages ship in D days with capacity C?" For split array, it's "can we split into at most M subarrays with max sum S?"

Your job: write isFeasible() as a standalone unit testable method. Keep it under five lines if possible. If it's longer, you're doing too much. Test it in isolation with edge cases — min values, max values, and exactly at the boundary. That function is the only code that touches the real problem. Get it right, and the binary search is free.

FeasibilityExample.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// io.thecodeforge — dsa tutorial

// The entire algorithm depends on this function
boolean isFeasible(int[] piles, int h, double speed) {
    int hoursUsed = 0;
    for (int pile : piles) {
        hoursUsed += (int) Math.ceil(pile / speed);
        if (hoursUsed > h) return false; // early exit
    }
    return true;
}

// Driver: binary search calls this ~30 times
int minEatingSpeed(int[] piles, int h) {
    int lo = 1, hi = 1_000_000_000;
    while (lo < hi) {
        int mid = lo + (hi - lo) / 2;
        if (isFeasible(piles, h, mid)) {
            hi = mid;
        } else {
            lo = mid + 1;
        }
    }
    return lo;
}

// Test it in isolation
// isFeasible([3,6,7,11], 8, 4.0) → true  (ceil(3/4)+ceil(6/4)+ceil(7/4)+ceil(11/4) = 1+2+2+3 = 8)
// isFeasible([3,6,7,11], 8, 3.0) → false (ceil(3/3)+ceil(6/3)+ceil(7/3)+ceil(11/3) = 1+2+3+4 = 10 > 8)
Output
isFeasible([3,6,7,11], 8, 4.0) returns true
isFeasible([3,6,7,11], 8, 3.0) returns false
Production Rule:
Write isFeasible() first. Test it in isolation with edge case inputs. Only then wrap it in binary search. If binary search gives wrong output, 99% of the time isFeasible() is the culprit.
Key Takeaway
Your entire binary search algorithm is only as correct as isFeasible(). If that function is wrong, nothing else matters.
● Production incidentPOST-MORTEMseverity: high

Wrong Minimum Because Feasibility Wasn't Monotonic

Symptom
The algorithm returned 45 seconds, but actual safe cooling time was 80 seconds. Servers overheated in production.
Assumption
Feasibility is monotonic: if cooling time T works, any T' > T also works.
Root cause
The thermal model had a resonance effect: at T=60s the cooling system oscillated and failed, but at T=90s it stabilised again. The feasibility function was not monotone.
Fix
Replaced binary search on answer with a full scan over plausible times after validating monotonicity with boundary checks.
Key lesson
  • Never assume monotonicity without proof. Plot feasibility for a handful of candidate values before trusting binary search.
  • Binary search on answer is correct only if condition(X) is monotonic in the answer space. A single counterexample breaks it.
Production debug guideSymptom → Action guide for engineers debugging check functions3 entries
Symptom · 01
Binary search returns a value that doesn't actually satisfy the condition when validated manually.
Fix
Check bounds: ensure lo/hi cover the full answer space. Add a post-loop sanity check: if condition(lo) is False, no feasible solution exists. If condition(lo) is True but lo is not the true min, the feasibility function may be correct but the search direction is wrong (min vs max).
Symptom · 02
Infinite loop: the algorithm never terminates.
Fix
Verify mid computation uses floor division for min-search (mid = (lo+hi)//2) and moves lo = mid+1 on fail. For max-search, use ceiling division or adjust mid+1 logic. Add a print(mid, lo, hi) inside the loop to see the search range.
Symptom · 03
Algorithm returns a suboptimal value: the condition is true but a smaller (or larger) answer exists.
Fix
The feasibility function might be too generous. Verify that condition(mid) truly represents the problem constraint. For example, in 'minimum days', ensure that the loop counting bouquets resets bloomed=0 correctly when a flower is not bloomed.
★ Quick Debug Cheat Sheet for Binary Search on AnswerUse these commands and checks when your parametric search behaves unexpectedly
Wrong answer returned (not minimal or maximal)
Immediate action
Print lo, hi, mid at each iteration. Verify that condition(mid) toggles from False to True exactly once.
Commands
Add debug: `print(f'lo={lo}, hi={hi}, mid={mid}, feasible={feasible}')` inside the loop
Test at three key points: lo, hi, and the expected answer from a brute-force solver
Fix now
If condition(lo) is True, your search range is too large; shrink hi. If condition(hi) is False, expand hi.
Infinite loop (lo and hi stop moving)+
Immediate action
Check mid calculation: for min-search use `mid = (lo + hi) // 2`. For max-search use `mid = (lo + hi + 1) // 2` else you may never converge.
Commands
Replace `while lo < hi:` with `while lo + 1 < hi:` and debug ranges
Add a max iteration counter: `iters = 0; while lo < hi and iters < 100: iters+=1`
Fix now
If using mid = (lo+hi)//2 and condition(mid) True -> hi=mid; else -> lo=mid+1. That ensures convergence for min-search.
Condition function is too slow (runtime blowup)+
Immediate action
Profile the feasibility function: it's called O(log(range)) times. If each call is O(N^2), total explodes.
Commands
Time one call: `import time; t0=time.time(); print(can_finish(42, data))`
Consider caching intermediate results if the feasibility function shares expensive computations across candidate evaluations.
Fix now
Optimise the feasibility function to O(N) or O(N log N). If impossible, replace binary search with a different approach (e.g., ternary search for unimodal functions).
Binary Search on Answer vs. Related Techniques
TechniqueUse CaseComplexityMonotonicity Required
Binary Search on AnswerMin/max in answer space with monotonic feasibilityO(n log range)Yes
Standard Binary SearchTarget in sorted arrayO(log n)Array must be sorted
Ternary SearchFind unimodal function's maximum/minimumO(log n)Unimodal (single peak)
Prefix Sum + Binary SearchRange queries on prefix sumsO(log n) per queryNot needed
Linear ScanSmall answer spaceO(n * range)Not needed

Key takeaways

1
Binary search on answer applies when the answer range is monotone
feasible at X implies feasible at X+1 (or X-1).
2
Total complexity = O(feasibility_check * log(answer_range)).
3
The template
lo=min_possible, hi=max_possible; reduce toward the optimum based on condition(mid).
4
For min-search
mid = (lo+hi)//2, if condition True → hi=mid, else lo=mid+1.
5
For max-search
mid = (lo+hi+1)//2, if condition True → lo=mid, else hi=mid-1.
6
Always assert monotonicity before trusting the result. Test with edge cases.

Common mistakes to avoid

4 patterns
×

Assuming monotonicity without validation

Symptom
Binary search returns a value that does not satisfy the condition when tested manually, or misses the true optimum.
Fix
Test feasibility at 5–10 equally spaced candidates in the range. If the condition toggles more than once (true, false, true), the function is not monotonic and binary search on answer is invalid.
×

Using wrong mid calculation for max-search

Symptom
Infinite loop or wrong answer — many developers copy the min-search template and forget to adjust mid to (lo+hi+1)//2.
Fix
For max-search, set mid = (lo + hi + 1) // 2. If condition(mid) is True, set lo = mid; else set hi = mid - 1.
×

Off-by-one in search range bounds

Symptom
Algorithm returns lo or hi that is clearly not the answer (e.g., returns max range when a smaller answer exists).
Fix
Ensure hi includes the physically maximum possible answer. For max-search, ensure lo includes the minimum possible answer. Crudely, set lo to 1 (or 0 if allowed) and hi to the largest value that could ever satisfy the condition.
×

Feasibility function uses floating point division

Symptom
Precision errors cause condition(mid) to oscillate near the boundary, leading to wrong results or infinite loops.
Fix
Use integer math with ceil division: (x + d - 1) // d. If floating point is unavoidable, add a small epsilon and use math.isclose.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01SENIOR
How do you identify a problem that can be solved with binary search on a...
Q02JUNIOR
Explain the difference between standard binary search and binary search ...
Q03JUNIOR
What is the time complexity of binary search on answer?
Q04SENIOR
Write a function that finds the minimum common ancestor distance using b...
Q01 of 04SENIOR

How do you identify a problem that can be solved with binary search on answer?

ANSWER
Look for a minimization or maximization problem where you can answer 'is candidate X feasible?' in polynomial time. The feasibility must be monotonic: if X works, all values larger (or smaller) also work. Common indicators: 'minimum time', 'maximum possible minimum', 'find the smallest k such that...'.
FAQ · 5 QUESTIONS

Frequently Asked Questions

01
How do I identify if a problem can be solved with binary search on answer?
02
What is the difference between binary search on answer and standard binary search?
03
How do I set lo and hi correctly?
04
Can binary search on answer handle floating-point answers?
05
What happens if the condition function is not monotonic?
N
Naren Founder & Principal Engineer

20+ years shipping performance-critical code where algorithms decide the bill. Everything here is grounded in real deployments.

Follow
Verified
production tested
May 23, 2026
last updated
1,554
articles · all by Naren
🔥

That's Searching. Mark it forged?

12 min read · try the examples if you haven't

Previous
Binary Search Algorithm
2 / 8 · Searching
Next
Linear Search Algorithm