Binary Search
Halve the range each step by comparing to the middle.
Approach
Keep [lo, hi] bounds and inspect the midpoint. If it equals the target you're done; if it's smaller search the right half, otherwise the left. Use lo + (hi − lo) / 2 for the midpoint and a consistent boundary convention to avoid infinite loops.
Time complexity
O(log n)
Space complexity
O(1)
Common mistake
Computing mid as (lo + hi) / 2 (can overflow) or mismatching the loop condition with how you update lo/hi.
Interactive walkthrough — step through it below, free and without an account
Problem
Given an array of distinct integers sorted in ascending order, determine the index of a specified target value. Return the target's index when it appears; otherwise return -1.
Examples
Input: nums = [-1, 0, 3, 5, 9, 12], target = 9
Output: 4
Input: nums = [2, 4, 7, 11, 15], target = 6
Output: -1
Problem
Problem
Given an array of distinct integers sorted in ascending order, determine the index of a specified target value. Return the target's index when it appears; otherwise return -1.
Problem and Goal
Learning goal: Recognize when a sorted array lets you eliminate half of the candidates at every step.
Core idea A sorted array gives us directional information. After comparing the target with the middle value, every element on one side can be ruled out. Instead of checking values one by one, binary search keeps only the half that could still contain the target.
Algorithm plan
- Start with the complete index range.
- Inspect the value at the midpoint.
- Return immediately if it equals the target.
- Keep the right half when the midpoint is too small; keep the left half when it is too large.
- Return
-1when no indices remain.
Micro-example
For [-1, 0, 3, 5, 9, 12] and target 9, the first midpoint is index 2, containing 3.
Because 3 < 9, indices 0 through 2 cannot contain the target.
Pitfalls
- Binary search requires sorted data.
- The returned position is an index, not the value itself.
- The search must eventually discard the midpoint or stop on it.
Recap
- Sorting creates a useful left/right decision.
- Each comparison removes about half the candidates.
- An empty final range means the target is absent.
Problem and Goal
Halve the candidates
Compare the target with the middle value, then discard the half that cannot contain it.
One comparison turns a large search into a smaller search.
Key Idea: Halve the Range
Learning goal: Explain why one midpoint comparison is enough to discard half of a sorted range.
Core idea
Suppose the active range is [lo, hi] and its midpoint is mid. If nums[mid] is smaller than the target, then every index at or left of mid contains a value that is also too small. If nums[mid] is larger, every index at or right of mid is too large. The sorted order turns one comparison into a complete elimination step.
Data structure model
The array stays unchanged; only two index bounds move:
| Variable | Meaning |
|---|---|
lo | Smallest index still possible |
hi | Largest index still possible |
mid | Index inspected this iteration |
Use the inclusive convention [lo, hi]. If the midpoint is too small, set lo = mid + 1; if it is too large, set hi = mid - 1.
Key insight
The active interval represents every index that could still hold the target. Bounds must preserve that invariant after every update.
Micro-example
With lo = 0, hi = 5, and mid = 2, the value 3 is too small for target 9.
The next valid interval is [3, 5], not [2, 5], because index 2 has already been checked.
Pitfalls
- Keeping
midafter a mismatch can cause an infinite loop. - Mixing inclusive bounds with exclusive updates makes the invariant unclear.
- A comparison is about values, while movement is about indices.
Recap
- Sorted order makes each half eliminable.
[lo, hi]contains all remaining candidates.- Use
mid + 1andmid - 1after checkingmid.
Key Idea: Halve the Range
Discard the midpoint and everything to its left.
Set `lo = mid + 1`
Main Approach and Boundary Convention
Learning goal: Implement binary search with a safe midpoint and updates that guarantee progress.
Core idea
We use a closed interval [lo, hi] and continue while lo <= hi. The midpoint is computed as lo + (hi - lo) / 2, with integer division. This form avoids adding two potentially large indices before dividing, and every mismatch removes the inspected midpoint from the next range.
Algorithm plan
- Initialize
lo = 0andhi = nums.length - 1. - While
lo <= hi, computemid = lo + (hi - lo) / 2. - Compare
nums[mid]withtarget. - Return
midif they are equal. - Set
lo = mid + 1whennums[mid] < target. - Otherwise set
hi = mid - 1. - Return
-1after the interval becomes empty.
while lo <= hi:
mid = lo + (hi - lo) / 2
if nums[mid] == target: return mid
if nums[mid] < target: lo = mid + 1
else: hi = mid - 1
return -1Micro-example
For lo = 3 and hi = 5, mid = 3 + (5 - 3) / 2 = 4.
If index 4 contains 9, the algorithm returns 4 without another update.
Pitfalls
(lo + hi) / 2can overflow in fixed-width integer languages.lo < hibelongs to a different boundary style; do not pair it casually with closed-interval updates.- Forgetting integer division can produce a non-integer index.
Recap
- Closed interval means loop while
lo <= hi. - Safe midpoint:
lo + (hi - lo) / 2. - Every failed check moves a bound beyond
mid.
Main Approach and Boundary Convention
| Convention | Loop condition | Left update | Right update |
|---|---|---|---|
| Closed interval `[lo, hi]` | `lo <= hi` | `lo = mid + 1` | `hi = mid - 1` |
| Half-open interval `[lo, hi)` | `lo < hi` | Usually `lo = mid + 1` | Usually `hi = mid` |
Walkthrough: Find 9
Learning goal: Trace every bound and midpoint change on one complete search.
Core idea
We will search [-1, 0, 3, 5, 9, 12] for 9 using the closed interval [lo, hi]. The first midpoint is index 2; since its value is too small, the target must lie strictly to its right. The next midpoint lands exactly on the target.
Algorithm plan
- Start with
lo = 0,hi = 5. - Compute the midpoint using the safe formula.
- Compare the midpoint value with
9. - Update only the bound that excludes the impossible half.
- Stop as soon as equality is observed.
Micro-example
Iteration 1: mid = 2, nums[mid] = 3; because 3 < 9, update lo to 3.
Iteration 2: mid = 4, nums[mid] = 9; return index 4.
Why it works
The target remains inside [lo, hi] until the equality check succeeds, and the interval shrinks from six candidates to three before the answer is found.
Pitfalls
- Do not move
hiwhen the midpoint is smaller than the target. - Do not return the midpoint value when the problem asks for its index.
- Preserve the original array order while moving only bounds.
Recap
[0, 5]becomes[3, 5]after comparing with3.- The next midpoint is
4. - The answer is index
4.
Walkthrough: Find 9
Step through the concrete example from the problem statement.
Pitfalls and Edge Cases
Learning goal: Diagnose the two implementation mistakes that most often break binary search.
Core idea Binary search is short, but its correctness depends on matching three choices: the midpoint formula, the interval convention, and the loop condition. A mathematically reasonable-looking update can still skip an answer or repeat the same midpoint forever if those choices disagree.
Algorithm plan
- For a closed interval, initialize
hiton - 1. - Loop while
lo <= hiso a one-element range is checked. - Use
mid = lo + (hi - lo) / 2. - After checking
mid, update withmid + 1ormid - 1. - Test an empty array only if the surrounding problem allows it.
Common pitfall
Computing mid as (lo + hi) / 2 can overflow in fixed-width integer languages. Prefer lo + (hi - lo) / 2.
Boundary mismatch
Do not mix lo <= hi with updates that keep mid, or mix a half-open convention with closed-interval initialization.
Micro-example
With lo = 3, hi = 3, lo <= hi is true, so the only remaining element is inspected.
After a mismatch, hi = mid - 1 creates hi = 2, making the range empty.
Pitfalls
- Returning
-1before checking the final singleton range. - Using
lo = midorhi = midwith an inclusive interval. - Assuming a missing target has a valid insertion index.
Recap
- Safe midpoint prevents overflow.
- Loop and updates must share one boundary convention.
- Singleton and absent-target cases expose off-by-one bugs.
Pitfalls and Edge Cases
For a closed interval `[lo, hi]` with `while lo <= hi`, which update is correct after `nums[mid] < target`?
Complexity and Wrap-Up
Learning goal: Relate the halving behavior to the O(log n) time bound and O(1) extra space.
Core idea
After each comparison, the active range is roughly half as large. After k iterations, about n / 2^k candidates remain; the range becomes constant-sized when 2^k is comparable to n, so k is O(log n). The algorithm stores only a few indices, regardless of the array length.
Algorithm plan
- Maintain the invariant that the target can only be inside
[lo, hi]. - Spend constant work computing
midand making one comparison. - Shrink the interval by at least one element, usually by about half.
- Stop on equality or when the interval becomes empty.
Micro-example
A range of 16 candidates shrinks approximately as 16 → 8 → 4 → 2 → 1.
The array is not copied, and no recursive call stack is needed.
Why it works
Sorted order justifies each discarded half, while the invariant ensures the undiscarded half still contains every possible answer.
Pitfalls
- Binary search is not
O(log n)on an unsorted array. - Recursive implementations may use
O(log n)stack space; the iterative version usesO(1). - A tiny constant-time loop body does not change the logarithmic number of iterations.
Recap
- Time:
O(log n)because the range is repeatedly halved. - Extra space:
O(1)for the iterative approach. - Correctness depends on sorted input and consistent boundaries.
Complexity and Wrap-Up
Visualize the cost of iterative binary search.
Now try it on your own problem
Paste any LeetCode problem — or one of your own — and codebrew builds a walkthrough like this one for it.
Build a lesson from any problem
