Binary Search on Answer Technique in DSA Java - Time & Space Complexity
We want to understand how fast the binary search on answer technique finds the correct answer.
How does the number of steps grow as the search range gets bigger?
Analyze the time complexity of the following code snippet.
int low = 0, high = maxPossibleAnswer;
while (low <= high) {
int mid = low + (high - low) / 2;
if (canAchieve(mid)) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return low;
This code tries to find the smallest value that satisfies a condition by repeatedly checking the middle of the current range.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The while loop that halves the search range each time.
- How many times: The loop runs about log base 2 of the size of the search range.
Each step cuts the search range in half, so the number of steps grows slowly even if the range grows a lot.
| Input Size (maxPossibleAnswer) | Approx. Operations (loop iterations) |
|---|---|
| 10 | About 4 |
| 100 | About 7 |
| 1000 | About 10 |
Pattern observation: Doubling the input size adds only one more step.
Time Complexity: O(log n)
This means the number of steps grows slowly, making it efficient for large search ranges.
[X] Wrong: "The loop runs n times because it checks every number in the range."
[OK] Correct: The loop does not check every number; it halves the range each time, so it runs much fewer times.
Understanding this technique shows you can solve problems efficiently by narrowing down answers quickly, a valuable skill in many coding challenges.
"What if the condition check inside the loop took linear time instead of constant time? How would the overall time complexity change?"
Practice
Binary Search on Answer technique?Solution
Step 1: Understand the technique's approach
Binary Search on Answer guesses a possible answer and checks if it meets the problem's conditions.Step 2: Adjust guess based on check
If the guess is valid, we try smaller or larger guesses accordingly to find the best answer.Final Answer:
We guess an answer and check if it satisfies the problem constraints, then adjust the guess. -> Option AQuick Check:
Guess and check approach = We guess an answer and check if it satisfies the problem constraints, then adjust the guess. [OK]
- Confusing with normal binary search on sorted arrays
- Thinking it only finds elements, not answers
- Assuming it divides data instead of answer range
Solution
Step 1: Define search range for answer
Minimum maximum load can be between 0 and sum of all loads because no worker can have load more than total.Step 2: Set low and high accordingly
Set low = 0 and high = sum of all loads to cover all possible answers.Final Answer:
low = 0; high = sum of all loads -> Option CQuick Check:
Search range covers all loads = low = 0; high = sum of all loads [OK]
- Setting low to minimum load instead of 0
- Setting high to max single load instead of sum
- Using average load as boundary
int[] pages = {10, 20, 30, 40};
int low = 40, high = 100;
while (low < high) {
int mid = (low + high) / 2;
if (canAllocate(pages, mid, 2)) {
high = mid;
} else {
low = mid + 1;
}
}
System.out.println(low);
// canAllocate checks if pages can be divided among 2 students with max pages mid
What will be the output?Solution
Step 1: Understand the problem and initial range
Pages array is {10,20,30,40}, low=40 (max single), high=100 (sum). We want minimum max pages for 2 students.Step 2: Trace binary search iterations
Mid = 70: canAllocate true (10+20+30=60 <=70 for 1st student, 40 for 2nd). So high=70.
Mid = 55: canAllocate false (10+20+30=60 >55). So low=56.
Mid = 63: canAllocate true (10+20+30=60 <=63, 40 for 2nd). high=63.
Mid = 59: canAllocate false (60 >59). low=60.
Mid = 61: canAllocate true. high=61.
Mid = 60: canAllocate true. high=60.
Mid = 60 again, low=60, high=60 ends loop.Final Answer:
60 -> Option BQuick Check:
Minimum max pages = 60 [OK]
- Not updating low/high correctly after canAllocate
- Misunderstanding canAllocate logic
- Incorrect mid calculation or loop condition
int[] nums = {7, 2, 5, 10, 8};
int m = 2;
int low = 0, high = 32;
while (low <= high) {
int mid = (low + high) / 2;
if (canSplit(nums, mid, m)) {
high = mid - 1;
} else {
low = mid + 1;
}
}
System.out.println(low);
// canSplit checks if nums can be split into m subarrays with max sum <= mid
Solution
Step 1: Check initial low value
Low is set to 0, but minimum largest sum can't be less than max element (10).Step 2: Correct low initialization
Set low = max element (10) to ensure valid search range and avoid infinite loop or wrong answer.Final Answer:
The initial low should be max element, not 0 -> Option AQuick Check:
Low must start at max element [OK]
- Starting low at 0 causing invalid mid values
- Using wrong loop condition causing infinite loop
- Misunderstanding canSplit return values
int[] jobs = {3, 6, 7, 11}; int k = 2;
Options:
Solution
Step 1: Define search boundaries
Low should be max job time (11), high sum of all jobs (3+6+7+11=27) to cover all possible times.Step 2: Use binary search with feasibility check
Check if jobs can be assigned to k=2 workers within mid time. Adjust low/high based on feasibility.Final Answer:
Set low = max job time, high = sum of all jobs; check if jobs can be assigned within mid time using k workers; adjust low/high accordingly. -> Option DQuick Check:
Binary search on answer with feasibility check = Set low = max job time, high = sum of all jobs; check if jobs can be assigned within mid time using k workers; adjust low/high accordingly. [OK]
- Setting wrong low/high boundaries
- Not checking feasibility properly
- Assigning jobs without binary search
Ready to prove it?
Pass the test and this pattern moves unknown
