Binary Search
Halving the search space on sorted data, and the many variants beyond a plain lookup.
Topic: Data Structures & Algorithms · Subject: Programming Fundamentals · Roles: AI Engineer, Data Scientist, Software Engineer
What it is
Binary search finds a target in a sorted search space by repeatedly comparing the target to the middle element and discarding the half that can't contain it. Each comparison halves the remaining space, giving O(log n) time.
The core loop
low, high = 0, n - 1
while low <= high:
mid = low + (high - low) // 2
if arr[mid] == target: return mid
elif arr[mid] < target: low = mid + 1
else: high = mid - 1
return -1 # not found
Use low + (high - low) / 2 rather than (low + high) / 2 to avoid integer overflow when both bounds are large.
Complexity
- Time: O(log n)
- Space: O(1) iterative, O(log n) recursive (call stack)
Variants beyond "find the exact value"
- First/last occurrence with duplicates — on a match, keep narrowing instead of returning immediately.
- Rotated sorted array — at least one half relative to
midis always still sorted; determine which, then decide where the target could be. - Binary search on the answer — search over a range of possible answers instead of array indices, using a monotonic feasibility check (e.g., "can we ship all packages within D days at capacity C?").
- Peak finding — compare
arr[mid]to its neighbor to decide which direction still has a peak.
Why it doesn't work on a linked list
Binary search's speed depends on O(1) access to the middle element. A linked list only supports sequential access, so finding "mid" costs O(n) — doing that at every step erases the entire advantage.
Practice Questions
Q1.What is the prerequisite for standard binary search to work correctly on an array?
Q2.What is the time complexity of binary search on a sorted array of n elements?
Q3.In the classic binary search loop, how is `mid` typically computed to avoid integer overflow?
Q4.What is the space complexity of an iterative binary search implementation?
Q5.What is the space complexity of a typical recursive binary search implementation, accounting for the call stack?
Q6.If arr[mid] < target in a standard ascending binary search, what should happen next?
Q7.What does binary search return, in a typical implementation, if the target is not found?
Q8.Which of these can binary search NOT be directly applied to?
Q9.What is "binary search on the answer" a technique for?
Q10.To find the first (leftmost) occurrence of a target in a sorted array with duplicates, what's a common modification to standard binary search?
Q11.What is the key property that makes binary search still applicable to a rotated sorted array like [4,5,6,7,0,1,2]?
Q12.What does lower_bound(target) typically return in binary search terminology?
Q13.What does upper_bound(target) typically return?
Q14.Why is binary search inefficient on a linked list even if it's sorted?
Q15.What's a common bug when a binary search loop uses `while (low < high)` when the algorithm's invariants require checking `low == high` too?
Q16.What is the maximum number of comparisons binary search needs, approximately, for an array of 1,000,000 elements?
Q17.How would you use binary search to find the square root of a non-negative number x to a given precision, without a built-in sqrt function?
Q18.What does it mean for a binary search "search space" to be monotonic, as required for binary-search-on-answer problems?
Q19.When searching a 2D matrix sorted both row-wise and globally (each row's values greater than the previous row's), what's a binary-search-friendly approach?
Q20.What does "peak element" search using binary search exploit, when finding an element greater than both its neighbors?
Q21.What's the time complexity of binary search combined with an O(n) preprocessing step, used to answer each of q queries?
Q22.Why might an interviewer ask you to implement binary search iteratively instead of recursively?
Q23.What happens to binary search's correctness if the array is sorted descending but the comparison logic assumes ascending order?
Q24.What is the relationship between binary search and the "divide and conquer" algorithmic paradigm?
Q25.If you need the closest value to a target when the exact target isn't present, what should you track during binary search?
Questions & Answers
Try answering in your head first, then click a question to check the model answer.
Q1.What are the prerequisites for binary search to work on an array?(show answer)
The array (or more generally, the search space) must be sorted, or more precisely have a property where you can determine, from any single element, which side of it the target would be on. Without that ordering property, discarding half the search space at each step isn't valid.
Q2.Walk through the core loop of binary search step by step.(show answer)
Maintain low and high bounds spanning the search space. While low <= high, compute mid = low + (high - low) / 2, compare arr[mid] to the target. If equal, return mid. If arr[mid] < target, the target must be in the right half, so set low = mid + 1. Otherwise set high = mid - 1. If the loop ends without a match, the target isn't present.
Q3.Why is `mid = low + (high - low) / 2` preferred over `mid = (low + high) / 2`?(show answer)
(low + high) can overflow in languages with fixed-width integers if both low and high are large, producing an incorrect (wrapped-around) value. low + (high - low) / 2 avoids ever summing two large numbers directly, while computing the same midpoint.
Q4.What's the time and space complexity of binary search, and why?(show answer)
O(log n) time, because each comparison eliminates half of the remaining search space, so it takes about log2(n) steps to narrow down to one element. Iterative implementations use O(1) extra space; recursive implementations use O(log n) space for the call stack, since recursion depth matches the number of halvings.
Q5.How do you modify binary search to find the first (leftmost) occurrence of a target in a sorted array containing duplicates?(show answer)
When you find a match (arr[mid] == target), don't return immediately — record it as a candidate answer, then keep searching the left half by setting high = mid - 1. This keeps narrowing toward the first occurrence rather than stopping at an arbitrary matching index.
Q6.How is finding the last (rightmost) occurrence different from finding the first?(show answer)
It's the mirror image: on a match, record the candidate and continue searching the right half by setting low = mid + 1 instead of narrowing left. Everything else about the loop is the same.
Q7.Explain how binary search can be applied to a rotated sorted array like [4,5,6,7,0,1,2].(show answer)
At each step, at least one half relative to mid is guaranteed to still be sorted normally, even though the array as a whole isn't. Check whether the left half (low to mid) is sorted; if so, determine whether the target lies within that range and search there, otherwise search the right half — and symmetrically if the right half is the sorted one instead.
Q8.What is "binary search on the answer," and when would you use it?(show answer)
Instead of searching array indices, you binary search over a range of possible answer values, using a feasibility check that is monotonic — once it flips from infeasible to feasible (or vice versa), it doesn't flip back. This applies to problems like "minimum capacity to ship packages within D days," where you binary search over possible capacities rather than searching an array directly.
Q9.Why doesn't binary search work efficiently on a linked list, even a sorted one?(show answer)
Binary search's efficiency depends on O(1) access to the middle element at every step. A linked list only supports sequential access, so finding the "middle" from a given pointer takes O(n) traversal — doing this at every step of what should be a logarithmic algorithm erases the benefit entirely, making it no better than a linear scan.
Q10.What's a common off-by-one bug in binary search, and how do you avoid it?(show answer)
Using while (low < high) when the algorithm's invariants actually require checking the case low == high (or vice versa), causing the search to loop infinitely or terminate one step too early and miss the target. The fix is to be deliberate about the loop invariant — decide up front exactly what low, high, and mid represent, and keep the boundary updates consistent with that invariant.
Q11.How would you find the square root of a non-negative number to a given precision using binary search?(show answer)
Binary search over a numeric range (e.g., 0 to x, or 0 to max(1, x)) instead of array indices. At each step, check if mid * mid is close enough to x within your precision tolerance; if mid * mid < x, search the upper half, otherwise search the lower half. This converges in O(log(x / precision)) steps.
Q12.What does it mean for a binary-search-on-answer problem to require a "monotonic feasibility function"?(show answer)
As you move through the range of candidate answers in one direction, the feasibility check must consistently switch from false to true (or true to false) exactly once, never flip back. This is what lets binary search safely discard half the candidate range at each step — if the function weren't monotonic, discarding a half could throw away the actual answer.
Q13.How can binary search be used to find a "peak element" (one greater than both neighbors) in an array in better than O(n)?(show answer)
Compare arr[mid] to arr[mid + 1]. If arr[mid] < arr[mid + 1], a peak must exist somewhere to the right (the sequence is still climbing), so search the right half; otherwise a peak exists to the left or at mid, so search the left half including mid. This works because a peak is guaranteed to exist in the direction the array is still increasing.
Q14.Describe an approach to search a 2D matrix that's sorted both row-wise and column-wise, where each row's values are all greater than the previous row's.(show answer)
Since the matrix is effectively a flattened sorted sequence, you can binary search over a single index from 0 to (rowscols - 1), converting it to a (row, col) pair via division and modulo by the column count, and compare as usual — giving O(log(rowscols)) instead of a full scan.
Q15.If binary search doesn't find an exact match, how do you determine the closest value in the array to the target?(show answer)
Track low and high as they converge; when the loop ends, low and high will have crossed such that arr[high] and arr[low] are the two closest surrounding candidates. Compare the target's distance to each and return whichever is closer, handling the boundary cases where one index is out of range.
Q16.Why is binary search considered a "divide and conquer" algorithm?(show answer)
Each step divides the problem (the search space) roughly in half, discards the half that can't contain the answer, and repeats on the remaining half — the core divide-and-conquer pattern of breaking a problem into a smaller version of itself, without needing to "combine" results afterward since only one half is ever kept.
Q17.What's the practical difference in an interview between implementing binary search iteratively versus recursively?(show answer)
Functionally they're equivalent, but iterative avoids call-stack overhead and the risk of stack depth issues, and it lets an interviewer directly observe how you manage loop invariants and pointer updates. Recursive versions can look cleaner but hide the same bookkeeping inside call parameters instead of loop variables.
Q18.How would binary search behave if mistakenly applied to a descending-sorted array using ascending-order comparison logic?(show answer)
It would consistently search the wrong half at each step — when arr[mid] < target, the algorithm assumes the target is to the right, but in a descending array the target would actually be to the left. It would likely terminate without finding an existing target, or return the wrong result.
Q19.How would you binary search for the minimum element in a rotated sorted array with no duplicates?(show answer)
Compare arr[mid] to arr[high]. If arr[mid] > arr[high], the minimum must be in the right half (the rotation point is to the right), so set low = mid + 1. Otherwise, the minimum is in the left half including mid, so set high = mid. This narrows to the rotation point, which holds the minimum.
Q20.What's the time complexity of answering q independent range queries on a static array, if you binary search into a precomputed prefix-sum array for each query?(show answer)
O(n) to build the prefix sum array once, plus O(log n) per query for the binary search, giving O(n + q log n) total — much better than recomputing from scratch for every query.
Q21.Why can't binary search be directly applied to an unsorted array?(show answer)
The core assumption of binary search — that comparing the target to the middle element tells you definitively which half to discard — only holds when the array's ordering guarantees everything before a boundary satisfies one condition and everything after satisfies another. In an unsorted array, the target could be on either side regardless of the comparison, so no half can be safely discarded.
Q22.What is the relationship between binary search and the number of comparisons needed, expressed as log2(n)?(show answer)
Each comparison halves the remaining search space, so after k comparisons, at most n / 2^k elements remain. Solving for when this shrinks to 1 gives k ≈ log2(n) — for example, an array of ~1,000,000 elements needs only about 20 comparisons in the worst case, versus up to 1,000,000 for linear search.
Q23.How would you use binary search to find the minimum capacity needed to ship all packages within D days?(show answer)
Binary search over possible capacities, from the maximum single package weight (the theoretical minimum feasible capacity) to the sum of all weights (always feasible in one day's worth of shipping capacity). For each candidate capacity, run a greedy O(n) simulation to check how many days it takes; if it fits within D days, try a smaller capacity, otherwise try a larger one.
Q24.What edge cases should you explicitly test for any binary search implementation?(show answer)
An empty array, a single-element array, the target being smaller than every element, the target being larger than every element, and the target matching the first or last element exactly — these boundary conditions are where off-by-one bugs in the loop condition or bound updates tend to surface.
Q25.Why is binary search often described as requiring you to "trust the invariant" rather than trace through every example?(show answer)
Verifying correctness by manually stepping through a few examples can miss subtle boundary bugs; instead, you define a precise invariant (e.g., "the answer, if it exists, is always within [low, high]") and prove that every loop iteration preserves that invariant. If the invariant holds at the start and is preserved by every update, correctness follows generally rather than just for the examples you happened to trace.