Skip to content
ΣDSA Patterns
Menu
Language

Pattern #04

Binary Search

Essential

Halve a sorted or monotonic search space until you pin the answer.

When to use

The search space is sorted, rotated-sorted, or any monotonic predicate “feasible(mid)”. not only classic “find target in array”.

Recognition cues

  • Sorted array (or partially ordered)
  • Find first/last/insert position
  • Rotated sorted array
  • Peak finding with bitonic property

Common pitfalls

  • Infinite loop: use lo < hi with exclusive bound, or lo + 1 < hi carefully
  • Mid overflow: prefer lo + ((hi - lo) >> 1)
  • Confusing lower-bound vs exact match

90-second recognition drill

Which pattern fits best?

  • Sorted array (or partially ordered)
  • Find first/last/insert position
  • Rotated sorted array

Interactive

Mental model

A full worked walkthrough of the invariant. Pause, scrub the dots, or use ← →. Aim to narrate each step yourself.

Step 1 of 8
-1
lo
0
3
5
mid
9
12

a[mid] = 5

Half-open search space [lo, hi). Target = 9.

How to think about it

Maintain an interval that must contain the answer. Probe the midpoint; discard half based on a monotonic test. Prefer the lower-bound form: lo = 0, hi = n (exclusive), shrink until lo == hi.

Template checklist

  1. What is the search space? (indices, values, answer range)
  2. What does feasible(mid) mean?
  3. Do you want the first true or last true?
  4. Handle empty arrays and single-element edge cases.

Complexity baseline

O(log n) time, O(1) space for iterative form.

Template

Same skeleton in TypeScript, Python, and C#. Adapt the invariant; keep the structure.

Binary Search · Template
/** Binary search template: lower-bound, then exact match. */
export function binarySearch(nums: number[], target: number): number {
  let lo = 0, hi = nums.length;
  while (lo < hi) {
    const mid = lo + ((hi - lo) >> 1);
    if (nums[mid]! < target) lo = mid + 1;
    else hi = mid;
  }
  return lo < nums.length && nums[lo] === target ? lo : -1;
}
/** Binary search template: lower-bound, then exact match. */
export function binarySearch(nums: number[], target: number): number {
  let lo = 0, hi = nums.length;
  while (lo < hi) {
    const mid = lo + ((hi - lo) >> 1);
    if (nums[mid]! < target) lo = mid + 1;
    else hi = mid;
  }
  return lo < nums.length && nums[lo] === target ? lo : -1;
}