Binary Search on Answer Technique in DSA Rust - 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 when the search range gets bigger?
Analyze the time complexity of the following code snippet.
fn binary_search_answer(low: i32, high: i32, check: fn(i32) -> bool) -> i32 {
let mut left = low;
let mut right = high;
while left <= right {
let mid = left + (right - left) / 2;
if check(mid) {
right = mid - 1;
} else {
left = mid + 1;
}
}
left
}
This code tries to find the smallest number in a range that satisfies a condition by repeatedly cutting the search space in half.
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 until the search range is empty, roughly halving the range each step.
Each step cuts the search range in half, so the number of steps grows slowly as the range grows.
| Input Size (range size) | Approx. Operations (loop iterations) |
|---|---|
| 10 | About 4 |
| 100 | About 7 |
| 1000 | About 10 |
Pattern observation: Doubling the input size adds only one more step, showing very slow growth.
Time Complexity: O(log n)
This means the number of steps grows slowly, only increasing by one each time the input size doubles.
[X] Wrong: "The binary search on answer takes linear time because it checks many values."
[OK] Correct: Actually, it does not check every value. It smartly cuts the search space in half each time, so it only needs a few checks even for large ranges.
Understanding this technique shows you can solve problems efficiently by narrowing down answers quickly, a skill valued in many coding challenges.
"What if the check function takes longer time to run? How would that affect the overall time complexity?"
Practice
Binary Search on Answer technique?Solution
Step 1: Understand the technique purpose
Binary Search on Answer guesses a possible answer and checks if it satisfies the problem's conditions.Step 2: Use binary search to narrow answer range
By checking mid-values and adjusting search space, we find the smallest or largest valid answer efficiently.Final Answer:
We guess an answer and use binary search to find the smallest or largest valid value. -> Option AQuick Check:
Binary Search on Answer = Guess + Check + Narrow [OK]
- Confusing it with normal binary search on sorted arrays
- Thinking it finds elements, not answers
- Assuming it works only on arrays
Solution
Step 1: Identify correct search range
The problem states searching between 1 and 100 inclusive, so low should be 1 and high 100.Step 2: Check boundary initialization
let mut low = 1; let mut high = 100; sets low = 1 and high = 100, which matches the problem range exactly.Final Answer:
let mut low = 1; let mut high = 100; -> Option DQuick Check:
Boundaries match problem range [OK]
- Starting low at 0 when range starts at 1
- Setting high to 101 which is outside the range
- Confusing inclusive and exclusive boundaries
fn binary_search_answer() -> i32 {
let mut low = 1;
let mut high = 10;
while low < high {
let mid = (low + high) / 2;
if mid * mid >= 10 {
high = mid;
} else {
low = mid + 1;
}
}
low
}
fn main() {
println!("{}", binary_search_answer());
}
What is the output when this program runs?Solution
Step 1: Understand the search condition
We want the smallest x where x*x >= 10. Squares: 3*3=9 (no), 4*4=16 (yes).Step 2: Trace binary search steps
Initial low=1, high=10 mid=5, 5*5=25 >=10, high=5 mid=3, 3*3=9 <10, low=4 mid=4, 4*4=16 >=10, high=4 Now low=4, high=4, loop ends, returns low=4.Final Answer:
4 -> Option AQuick Check:
Minimum x with x*x >= 10 is 4 [OK]
- Returning mid instead of low after loop
- Off-by-one errors in updating low or high
- Confusing condition direction (>= vs >)
fn max_x() -> i32 {
let mut low = 0;
let mut high = 20;
while low <= high {
let mid = (low + high) / 2;
if mid * mid <= 20 {
low = mid;
} else {
high = mid - 1;
}
}
high
}Solution
Step 1: Analyze loop update statements
When mid equals low, setting low = mid does not change low, causing infinite loop.Step 2: Identify fix for infinite loop
To avoid infinite loop, update low to mid + 1 when condition holds.Final Answer:
The update 'low = mid' can cause infinite loop when low == mid. -> Option BQuick Check:
Update low to mid + 1 to progress loop [OK]
- Not updating low or high correctly causing infinite loops
- Returning wrong boundary after loop ends
- Confusing loop condition operators
Solution
Step 1: Define answer range and check function
We binary search over possible maximum time per worker. For each mid, we check if tasks can be assigned in order without exceeding mid time per worker.Step 2: Greedy assignment check
Assign tasks to workers greedily, moving to next worker when current sum exceeds mid. If all tasks fit within allowed workers, mid is valid.Final Answer:
Binary search the answer range of time, and for each mid, greedily assign tasks to workers checking if all tasks fit within mid time. -> Option CQuick Check:
Binary Search on Answer + Greedy check = Correct approach [OK]
- Sorting tasks when order matters
- Binary searching worker count instead of time
- Assigning tasks randomly ignoring order
Ready to prove it?
Pass the test and this pattern moves unknown
