When interviewers ask you to "find the minimum X that satisfies a condition" or "search over a range of values", they are usually pointing at a modified binary search. The classic binary search looks for a target value in a sorted array. The modified version, sometimes called "binary search on answer", turns the search space into a numeric interval or an index range and uses a monotonic predicate to guide the cut. [] []
Why Binary Search on Answer Exists
Traditional binary search solves the problem of locating an element in a sorted list in (O(\log n)). Many interview problems are not about locating an existing element but about finding a boundary where a condition flips from false to true. If the predicate is monotonic—once true it stays true—then you can treat the answer itself as a sorted space and binary‑search it. This reduces a potentially (O(n)) or (O(n\log n)) brute‑force solution to (O(\log M)) where (M) is the size of the numeric domain.
Signals in the Statement
| Signal | Typical Wording |
|---|---|
| "minimum/maximum" | "Find the smallest capacity…" |
| "feasible" or "possible" | "Determine if a value X can be achieved…" |
| "kth" or "order" | "Return the kth smallest …" |
| "range of values" | "Given a budget B, maximize …" |
| "monotonic" | "The function f(i) is non‑decreasing…" |
If you see any of these, pause and ask yourself whether the predicate can be evaluated quickly. If yes, you likely have a modified binary search.
Core Template
def binary_search(low, high, predicate):
# invariant: predicate(low) is False, predicate(high) is True
while low + 1 < high:
mid = (low + high) // 2
if predicate(mid):
high = mid # keep the true side
else:
low = mid # keep the false side
return high # the smallest true value
- Choose
lowandhighso that the answer lies strictly between them. predicatemust run in at most (O(\log n)) to keep the overall complexity low.- Adjust the return based on whether you need the smallest true or largest false.
Complexity and Pitfalls
- Time – Each iteration halves the search interval, so you get (O(\log M)) calls to the predicate. If the predicate itself is (O(\log n)), the total is (O(\log M \cdot \log n)).
- Space – Usually constant, unless the predicate uses recursion.
- Off‑by‑one – The most common bug. Ensure the invariant correctly reflects the state of
lowandhigh. A good trick is to start withlow = -1andhigh = max_possible + 1when the domain is non‑negative. - Non‑monotonic predicates – If the condition can flip back and forth, binary search will return a wrong answer. Validate monotonicity with a couple of manual checks.
- Overflow – In languages with fixed‑size integers,
mid = low + (high - low) // 2avoids overflow; Python’s big ints make this less of a concern.
Worked Example: Allocate Minimum Shipping Capacity
Problem: You have n packages with weights w[i]. You need to ship them in order using the fewest containers possible, each container can hold at most C weight. Find the smallest C that allows shipping all packages using at most k containers.
Observation: If a capacity C works, any larger capacity also works – the predicate can_ship(C) is monotonic.
Predicate:
def can_ship(C):
containers = 1
cur = 0
for weight in w:
if weight > C:
return False # single package exceeds capacity
if cur + weight > C:
containers += 1
cur = weight
else:
cur += weight
return containers <= k
Search bounds: low = max(w) - 1 (guaranteed false) and high = sum(w) + 1 (guaranteed true).
Putting it together:
def min_capacity(w, k):
low, high = max(w) - 1, sum(w) + 1
while low + 1 < high:
mid = (low + high) // 2
if can_ship(mid):
high = mid
else:
low = mid
return high
The loop runs about log2(sum(w) - max(w)) times, each iteration scans the array once – overall (O(n \log W)) where W is the weight range.
Five Practice Problems
- Kth Smallest Pair Distance – Given an array
nums, find the kth smallest absolute difference between any two elements. Hint: Use binary search on the distance and count pairs with a two‑pointer scan. - Split Array Largest Sum – Partition an array into
msubarrays so that the largest sum among them is minimized. Hint: Predicate checks if you can split with a given maximum sum. - Maximum Length of Subarray With Sum ≤ S – Find the longest subarray whose sum does not exceed
S. Hint: Binary search the length and verify feasibility with a sliding window. - Minimum Days to Make Bouquets – You have bloom days for flowers; you need
mbouquets ofkconsecutive flowers. Find the earliest day you can make them. Hint: Predicate tests if a daydallows forming enough bouquets. - Allocate Minimum Number of Pages – Distribute
nbooks (pages array) tomstudents so that the maximum pages assigned to any student is minimized. Hint: Same pattern as the shipping capacity example.
Each problem follows the same skeleton: define a monotonic predicate, set tight low/high bounds, and run the loop.
How to Practice This
- Pick a problem from the list, write the predicate first, and test it on a few small inputs.
- Implement the binary search template exactly as shown, then run it against the same inputs.
- Rehearse your explanation aloud, perhaps using Call Assistant to keep the narrative focused and to receive quick feedback on clarity.
FAQ
Q: When should I prefer a modified binary search over a sliding window? A: Use modified binary search when the answer is a numeric value you can binary‑search and the predicate can be evaluated in sub‑linear or linear time. Sliding windows are better for direct enumeration of contiguous subarrays.
Q: Can I use recursion instead of a loop? A: Yes, but iterative loops avoid stack depth issues and are easier to reason about for interviewers.
Q: What if the predicate is O(n) and the search space is large (e.g., up to 10⁹)? A: The total time becomes (O(n \log 10⁹)), which is usually acceptable for interview constraints (n up to 10⁵). If n is also huge, look for ways to make the predicate faster, perhaps with prefix sums.
Q: How do I prove monotonicity on the spot? A: Explain the logical relationship: increasing the candidate value can only add more feasible options, never remove them. A quick example or counter‑example helps convince the interviewer.
Frequently asked questions
When should I use modified binary search instead of brute force?
If the problem asks for the smallest/largest value that satisfies a condition and you can test that condition quickly, binary search reduces the search from linear to logarithmic time.
What is the typical loop condition for the search?
Use `while low + 1 < high` to maintain a strict false/true invariant, then return the boundary that satisfies the predicate.
How can I avoid off‑by‑one errors?
Initialize `low` to a value that is definitely false and `high` to a value that is definitely true; then step through a couple of manual iterations to verify the invariant.
Is binary search on answer only for numeric domains?
Mostly, but you can also apply it to index ranges or any ordered set where you can define a monotonic predicate.
#coding pattern#modified binary search#interview prep#algorithm#python