Binary Search on Answer Concept
Binary search on answer is a powerful technique for solving optimization problems where we binary search on the answer space rather than the array.
When to Use
Use binary search on answer when:
- You need to find minimum/maximum value satisfying a condition
- The answer space is monotonic - if value
xworks, all values> x(or< x) also work - You can efficiently check feasibility for a given value
The Pattern
// Template for binary search on answer
public int binarySearchOnAnswer(int[] arr) {
int low = minValue; // Minimum possible answer
int high = maxValue; // Maximum possible answer
while (low < high) {
int mid = low + (high - low) / 2;
if (isFeasible(arr, mid)) {
high = mid; // Try to find smaller answer
} else {
low = mid + 1; // Need larger answer
}
}
return low; // Minimum feasible answer
}
// Check if mid is a valid answer
boolean isFeasible(int[] arr, int value) {
// Check if 'value' satisfies the constraint
// Return true if feasible, false otherwise
}
Example: Minimum Capacity to Ship Packages
// Problem: Ship packages within D days with minimum capacity
// Binary search on capacity (answer)
public int shipWithinDays(int[] weights, int days) {
int low = 0; // Minimum capacity: max weight
int high = 0; // Maximum capacity: sum of all weights
for (int w : weights) {
low = Math.max(low, w);
high += w;
}
while (low < high) {
int mid = low + (high - low) / 2;
if (canShipWithinDays(weights, days, mid)) {
high = mid; // Try smaller capacity
} else {
low = mid + 1; // Need larger capacity
}
}
return low;
}
boolean canShipWithinDays(int[] weights, int days, int capacity) {
int currentLoad = 0;
int daysNeeded = 1;
for (int w : weights) {
if (currentLoad + w > capacity) {
daysNeeded++;
currentLoad = 0;
}
currentLoad += w;
}
return daysNeeded <= days;
}
Complexity Analysis
- Time: O(n × log(sum - max)) where n is array length
- Space: O(1)
The binary search runs in O(log(sum - max)) iterations, each requiring O(n) feasibility check.
Designing Feasibility Functions
The key to binary search on answer is designing an efficient feasibility function that checks if a given value works.
Common Feasibility Patterns
1. Greedy Check
// Check if we can split array into k parts with max sum <= target
boolean canSplit(int[] nums, int k, int target) {
int count = 1;
int currentSum = 0;
for (int num : nums) {
if (currentSum + num > target) {
count++;
currentSum = num;
if (count > k) return false;
} else {
currentSum += num;
}
}
return true;
}
2. Counting Check
// Check if we can place m balls with minimum distance >= target
boolean canPlace(int[] positions, int m, int target) {
int count = 1;
int lastPosition = positions[0];
for (int i = 1; i < positions.length; i++) {
if (positions[i] - lastPosition >= target) {
count++;
lastPosition = positions[i];
if (count >= m) return true;
}
}
return false;
}
3. Binary Search within Feasibility Check
// Check if median is <= target
boolean isMedianBelowTarget(int[] nums, int target) {
int countLess = 0;
for (int num : nums) {
if (num <= target) countLess++;
}
return countLess > nums.length / 2;
}
Example: Magnetic Force Between Balls
public int maxDistance(int[] position, int m) {
Arrays.sort(position);
int low = 1;
int high = position[position.length - 1] - position[0];
while (low < high) {
int mid = low + (high - low + 1) / 2; // Ceil division
if (canPlaceBalls(position, m, mid)) {
low = mid; // Try larger distance
} else {
high = mid - 1; // Need smaller distance
}
}
return low;
}
boolean canPlaceBalls(int[] position, int m, int minForce) {
int count = 1;
int lastPos = position[0];
for (int i = 1; i < position.length; i++) {
if (position[i] - lastPos >= minForce) {
count++;
lastPos = position[i];
if (count >= m) return true;
}
}
return false;
}
Tips for Designing Feasibility Functions
- Greedy approach: Usually O(n) time
- Monotonic property: If value x works, all values > x (or < x) also work
- Clear boundary: Define what "works" means clearly
- Edge cases: Handle empty input, single element
Common Binary Search on Answer Problems
| Problem | Answer Space | Feasibility Check |
|---|---|---|
| Ship packages | Capacity | Greedy simulation |
| Split array | Maximum sum | Greedy counting |
| Magnetic force | Distance | Greedy placement |
| Koko eating bananas | Eating speed | Time calculation |
Practice Problems
Given an integer array nums and an integer k, split nums into k non-empty contiguous subarrays. Minimize the largest sum among these subarrays.
Example:
Input: nums = [7,2,5,10,8], k = 2
Output: 18
Split into [7,2,5] and [10,8]. Largest sum = max(14, 18) = 18.
Optimal Solution — O(n * log(sum)) time, O(1) space
Binary search on the answer (largest sum). Feasibility check: greedy split.
class Solution {
public int splitArray(int[] nums, int k) {
int low = 0, high = 0;
for (int num : nums) {
low = Math.max(low, num);
high += num;
}
while (low < high) {
int mid = low + (high - low) / 2;
if (canSplit(nums, k, mid)) high = mid;
else low = mid + 1;
}
return low;
}
private boolean canSplit(int[] nums, int k, int maxSum) {
int count = 1, sum = 0;
for (int num : nums) {
if (sum + num > maxSum) { count++; sum = num; }
else sum += num;
}
return count <= k;
}
}Edge Cases:
- k == 1
- k == n
- All same elements
A conveyor belt has packages to ship within D days. Return the minimum capacity of a ship that will ship all packages within D days.
Example:
Input: weights = [1,2,3,4,5,6,7,8,9,10], days = 5
Output: 15
Ship capacity 15 can ship in 5 days: [1,2,3,4,5],[6,7],[8],[9],[10]
Optimal Solution — O(n * log(sum)) time, O(1) space
Binary search on capacity. Feasibility: greedy loading.
class Solution {
public int shipWithinDays(int[] weights, int days) {
int low = 0, high = 0;
for (int w : weights) {
low = Math.max(low, w);
high += w;
}
while (low < high) {
int mid = low + (high - low) / 2;
if (canShip(weights, days, mid)) high = mid;
else low = mid + 1;
}
return low;
}
private boolean canShip(int[] weights, int days, int capacity) {
int count = 1, sum = 0;
for (int w : weights) {
if (sum + w > capacity) { count++; sum = w; }
else sum += w;
}
return count <= days;
}
}Edge Cases:
- days == 1
- days == n
- All same weight
Koko loves bananas. She has piles of bananas and h hours to eat. Return the minimum integer k such that she can eat all bananas within h hours.
Example:
Input: piles = [3,6,7,11], h = 8
Output: 4
Eat 4 per hour: 1+2+2+3 = 8 hours.
Optimal Solution — O(n * log(max(piles))) time, O(1) space
Binary search on eating speed k. Feasibility: check hours needed.
class Solution {
public int minEatingSpeed(int[] piles, int h) {
int low = 1, high = 1000000000;
while (low < high) {
int mid = low + (high - low) / 2;
if (canFinish(piles, h, mid)) high = mid;
else low = mid + 1;
}
return low;
}
private boolean canFinish(int[] piles, int h, int k) {
int hours = 0;
for (int p : piles) {
hours += (p + k - 1) / k;
}
return hours <= h;
}
}Edge Cases:
- h == piles.length
- All piles size 1
- One huge pile
Quiz
1. In binary search on answer, what property must the feasibility function satisfy?
2. When binary searching for minimum feasible answer, when should you set `high = mid` vs `low = mid + 1`?
3. What is the primary purpose of Binary Search on Answer?
4. What is a common mistake when implementing Binary Search on Answer?
Flashcards
Question
When should you use binary search on answer?
Click to reveal answer
Answer
When finding minimum/maximum value satisfying a condition, and the answer space has monotonic feasibility property.
Question
What is the typical time complexity of binary search on answer?
Click to reveal answer
Answer
O(n × log(answer_space)) - n for feasibility check, log for binary search iterations.
Question
What is Binary Search on Answer?
Click to reveal answer
Answer
Binary Search on Answer is a key concept in software engineering.
Question
When to use Binary Search on Answer?
Click to reveal answer
Answer
Use Binary Search on Answer when building production systems that require reliability, scalability, and maintainability.
Question
Binary Search on Answer best practices
Click to reveal answer
Answer
Follow SOLID principles, write clean code, test thoroughly, document decisions, and monitor in production.
Revision Notes
Key Takeaways
- 1.Binary search on answer finds optimal value in logarithmic iterations
- 2.Feasibility function must be monotonic for binary search to work
- 3.Define answer space boundaries clearly before starting
- 4.Greedy feasibility checks are common and efficient
Interview Tips
- •Clearly define what 'feasible' means for the problem
- •Discuss the monotonic property with interviewer
- •Start with brute force feasibility, then optimize
- •Handle edge cases in answer space boundaries
Cheat Sheet
Binary Search on Answer Cheat Sheet
Pattern:
int low = minAnswer, high = maxAnswer;
while (low < high) {
int mid = low + (high - low) / 2;
if (isFeasible(mid)) high = mid;
else low = mid + 1;
}
return low;
Key Steps:
- Define answer space (min to max possible)
- Design feasibility function (usually O(n))
- Binary search on answer space
- Return minimum/maximum feasible value
When to Use:
- Finding minimum/maximum with constraint
- Monotonic feasibility property
- O(n) feasibility check available