Binary Search Interview Problems — Off-by-One Traps
Using < instead of <= when left == mid breaks rotated array search silently.
- Binary search eliminates half the search space per guess — O(log n) instead of O(n)
- Pattern 1: Standard value search on sorted array (LeetCode 704)
- Pattern 2: Boundary search for first/last occurrence in duplicates (LeetCode 34)
- Pattern 3: Rotated array search — determine sorted half and decide (LeetCode 33)
- Pattern 4: Answer-space search — binary search on answer range, not input (LeetCode 875)
- Performance: 1 billion sorted elements require at most 31 comparisons — but off-by-one bugs cause silent infinite loops in production
Imagine you're looking up a word in a physical dictionary. You don't start from page 1 — you crack it open in the middle, decide whether your word comes before or after that page, then repeat with the surviving half. That's binary search: you eliminate half the possibilities with every single guess. A 1000-page dictionary only needs about 10 guesses. That's the power — and that's exactly what interviewers are testing when they ask you to 'find something efficiently in a sorted structure'.
Binary search shows up in roughly 15-20% of technical screening rounds at top tech companies — not because it's exotic, but because it's a clean signal for how a candidate thinks about elimination, boundaries, and edge cases under pressure. Miss the pattern and you'll write an O(n) linear scan where an O(log n) search was expected. Spot it and you look like the engineer who actually understands algorithmic trade-offs.
The real problem isn't the algorithm itself — most people can recite 'split in half, compare, repeat'. The problem is recognizing WHEN to apply it, and then getting the boundary conditions exactly right without an off-by-one bug that only surfaces on arrays of length 1 or 2. Interviewers know this, which is why they love edge cases like single-element arrays, all-duplicate arrays, and rotated sorted arrays.
By the end of this article you'll be able to identify the four core binary search patterns by sight, implement each one without looking up the boundary conditions, and explain your reasoning out loud — which is exactly what interviewers want to hear. We'll go from the textbook template all the way through rotation, condition-based search, and answer-space binary search with full runnable code for each.
The Template That Eliminates Off-By-One Bugs Forever
Every binary search variant is a specialization of one template. Until you've internalized this template so deeply that you can write it in your sleep, you'll keep making subtle off-by-one errors that cause infinite loops or miss the target by one index.
The key design decision in any binary search is: what does your loop invariant guarantee? The invariant we'll use is this — the answer, if it exists, is always inside the closed interval [left, right]. That single rule dictates every boundary choice that follows.
When left == right there's exactly one candidate left. That's why the loop condition is left <= right, not left < right. And when you calculate mid, you use left + (right - left) / 2 instead of (left + right) / 2 — both give the same index, but the second one silently overflows when left and right are large integers, a bug that killed a famous Java binary search implementation in the JDK for nearly a decade.
The moment you find target at mid, you return immediately. If target < array[mid], the right half is useless, so right = mid - 1. If target > array[mid], the left half is useless, so left = mid + 1. This is the foundation every other pattern builds on.
(left+right)/2 stayed in Java's Arrays.binarySearch for years.mid = left + (right - left)/2 — safe, no overflow, one extra subtraction costs nothing.(left+right)/2 — always left + (right-left)/2.Finding Boundaries: First and Last Position of a Duplicated Target
Once you've nailed the classic template, the first upgrade interviewers throw at you is: 'What if the array has duplicates? Find the first occurrence, or the last occurrence.' This is LeetCode 34, and it's a direct test of whether you understand binary search deeply or just memorized the basic version.
The trick is to NOT return the moment you find the target. Instead, you record the current mid as a candidate answer, then deliberately push the search boundary to keep looking. For the first occurrence you push right = mid - 1 (keep searching left). For the last occurrence you push left = mid + 1 (keep searching right).
This turns a single-target search into a boundary search. The loop still terminates — left and right still converge — but now instead of exiting early you let the loop exhaust all possibilities, always keeping the best answer you've seen so far.
This pattern has a name: Left Boundary Binary Search and Right Boundary Binary Search. Recognizing them as named patterns rather than one-off tricks is what lets you adapt quickly when interviewers change the constraint mid-question.
ans, then keep narrowing the side you're searching.Searching a Rotated Sorted Array — The Classic Hard-Mode Variant
Here's where interviewers separate people who 'know binary search' from people who truly understand it. A rotated sorted array is an array like [40, 55, 63, 7, 18, 29] — it was originally sorted but has been rotated around a pivot. Half the array is still sorted. That's the key insight.
At every mid-point you can determine in O(1) which half is sorted — just compare array[left] with array[mid]. If array[left] <= array[mid], the left half is cleanly sorted. Otherwise, the right half is. Once you know which half is sorted, you can check in O(1) whether the target falls inside that sorted half. If yes, search there. If no, search the other half.
You never need to find the pivot explicitly. The binary search logic handles everything in one pass. That's the elegant part — and it's also what trips people up who try to pre-compute the pivot index before searching. Two passes where one will do is a sign of incomplete understanding, and interviewers notice.
< instead of <= when comparing nums[left] <= nums[mid] — causes misclassification of sorted half when mid equals left.<= for the sorted-half check; a single-element range is still sorted.<= when checking if left half is sorted.<= vs < bug hides.Answer-Space Binary Search — When the Input Isn't Even an Array
This is the pattern that separates intermediate from advanced binary search practitioners — and it trips up even experienced engineers. Answer-space binary search applies when you can't binary search the input directly, but you CAN binary search the space of possible answers.
The template is: define a minimum and maximum possible answer (your left and right pointers). Write a feasibility function that checks 'is this candidate answer good enough?'. Then binary search over the answer space, always recording the best valid answer found so far. This is the most powerful and least-recognized form of binary search in interview settings.
Finding Square Root Using Binary Search — Integer Square Root with Precision
A classic answer-space binary search example: find the integer square root of a non-negative integer x. You don't need Math.sqrt or Newton's method — binary search over [0, x] works beautifully and is often what interviewers expect for LeetCode 69 (Sqrt(x)).
The feasibility function is simple: check if mid * mid <= x. If yes, move left to mid + 1 (the square root could be larger). If no, move right to mid - 1. Record the candidate answer (mid) each time the check passes, because the last valid mid before the loop ends is the integer square root.
This problem is a perfect warm-up before tackling more complex answer-space problems like Koko Eating Bananas or Split Array Largest Sum. It's also a good test of overflow handling — mid * mid can overflow int if x is large. Use long for the multiplication.
- The answer space is [0, x] — but we can start left at 1 because sqrt(0)=0 is trivial.
- Feasibility:
mid * mid <= x— if true, the true sqrt is at least mid. - Overflow trap:
mid * midexceeds int range for x > 46340. Cast to long to avoid silent rollover. - Why record ans inside loop? Because the last time the condition passes is the integer floor of sqrt.
Searching a 2D Sorted Matrix with Binary Search
Interviewers often combine matrix traversal with binary search. LeetCode 240 (Search a 2D Matrix II) presents a matrix where rows and columns are sorted independently. The trick is to start from the top-right corner: you can eliminate an entire row or column in each step.
But there's also a binary search pattern here: if you treat each row as a sorted array, you could binary search each row individually — O(m log n). Or you could use the 'staircase' approach which is O(m+n). The interview trick is to recognise when the matrix is 'row and column sorted' vs 'fully sorted row-major' (LeetCode 74). For fully sorted row-major, you can flatten the matrix logically (using modulo arithmetic) and do one binary search in O(log(m*n)).
Know which variant you face: if the first element of each row is > last element of previous row, it's row-major sorted and you can do a true 2D binary search. If only rows and columns are sorted individually, use the top-right elimination method.
Off-by-One in Rotated Array Search Causes Null Pointer in Production Indexer
if (nums[left] <= nums[mid]), the condition used < instead of <=. When left == mid (two-element array), the left half was incorrectly identified as unsorted, causing the search to skip the target in the right half and eventually throw a NullPointerException when mid went out of bounds on the recursion recovery path.nums[left] <= nums[mid] and added a unit test that specifically tests arrays of length 2 with the target at the second position.- Always test rotated array search on arrays of length 1 and 2 — those are where boundary conditions hide.
- Use
<=when checking if a half is sorted by comparing nums[left] with nums[mid]; if left == mid, a single-element range is still sorted. - Never assume test coverage on a variety of sizes is enough — edge-case arrays are where off-by-one bugs live.
while (left <= right) not left < right. Ensure that when target != array[mid], you set right = mid - 1 or left = mid + 1 — never leave right = mid without also adjusting.left < right, add a post-loop check: return array[left] == target ? left : -1. Better yet, switch to left <= right.left, right, mid, ans after each iteration. Verify that after finding target == array[mid], you don't return early — instead record ans = mid and continue narrowing the side you're searching.if (array[left] <= array[mid]). For length-2 arrays, mid=0, so array[0] <= array[0] must be true to correctly identify left half as sorted. If you used <, left half is misclassified as unsorted.right = mid - 1 or left = mid + 1 after comparing array[mid] with target.Key takeaways
Common mistakes to avoid
5 patternsUsing left < right instead of left <= right
Writing right = mid instead of right = mid - 1 when array[mid] != target
In answer-space binary search, setting initial bounds wrong (e.g., left = 0 for ship capacity)
In rotated array search, using `nums[left] < nums[mid]` instead of `<=`
nums[left] <= nums[mid] to correctly classify a single-element range as sorted.In boundary search, returning early when target is found instead of continuing to narrow
Interview Questions on This Topic
LeetCode 33: Search in Rotated Sorted Array. How do you handle the search when you cannot find the pivot point explicitly in O(1)?
Frequently Asked Questions
That's Coding Patterns. Mark it forged?
5 min read · try the examples if you haven't