ALGORITHM LAB / EASY

Binary Search

Repeatedly cut a sorted search space in half. Follow every pointer update and comparison.

Time O(log n)Space O(1)Sorted input
lowmidhigh
4
0
lowmidhigh
11
1
lowmidhigh
18
2
lowmidhigh
29
3
lowmidhigh
37
4
lowmidhigh
51
5
lowmidhigh
64
6
lowmidhigh
73
7
lowmidhigh
82
8
lowmidhigh
96
9
Step 1/5Search for 73 across 10 sorted values.
Time O(log n)Space O(1)Range 10
binarySearch.tsTypeScript
01let low = 0, high = values.length - 1;02while (low <= high) {03  const mid = Math.floor((low + high) / 2);04  if (values[mid] === target) return mid;05  if (values[mid] < target) {06    low = mid + 1;07  } else {08    high = mid - 1;09  }10}11return -1;
01

Invariant

If the target exists, it always remains inside the inclusive [low, high] range.

02

Why logarithmic?

Each comparison removes half of the remaining candidates, producing at most log base 2 of n decisions.

03

Failure mode

Using binary search on unsorted input breaks the elimination rule, even when pointer code looks correct.

01

Overview

Binary search finds a target in a sorted collection by repeatedly comparing it with the middle element and discarding the half that cannot contain it. Every comparison removes about half of the remaining candidates, so a million sorted items need at most 20 comparisons.

The core idea is bigger than searching arrays. Binary search works on any search space where a yes/no question is monotonic: once the answer becomes true, it stays true. That is why the same technique solves problems like finding the minimum ship capacity, the first bad software version, or the square root of a number.

Guessing a number between 1 and 100

If someone answers only higher or lower, the best first guess is 50. Each answer throws away half of the remaining numbers, so you never need more than 7 guesses. Binary search is exactly this strategy applied to indexes of a sorted array.

02

When to use it

  • The input is sorted, or the answer space is ordered (numbers, indexes, time, capacity).
  • You can write a predicate that is false for one prefix and true for the rest (monotonic).
  • You need better than O(n) lookups and the data supports O(1) random access.
  • The problem says: minimum value that satisfies..., maximum value such that..., first or last position of...
03

Problem patterns it solves

Classic lookup in sorted data

Recognize it when: The array is sorted and you must find whether, or where, a value exists.

  • 704. Binary Search
  • 74. Search a 2D Matrix
  • 35. Search Insert Position
Boundary search (lower / upper bound)

Recognize it when: first or last position, first element >= x, count occurrences, first true.

  • 34. Find First and Last Position
  • 278. First Bad Version
  • 1351. Count Negative Numbers in a Sorted Matrix
Binary search on the answer

Recognize it when: minimize the maximum, maximize the minimum, minimum speed / capacity / days, and a feasible(x) check that flips once.

  • 875. Koko Eating Bananas
  • 1011. Capacity To Ship Packages
  • 1552. Magnetic Force Between Two Balls
  • 410. Split Array Largest Sum
  • 1482. Minimum Days to Make m Bouquets
Modified sorted arrays

Recognize it when: rotated, mountain, bitonic, or peak; one side of mid is still ordered.

  • 33. Search in Rotated Sorted Array
  • 153. Find Minimum in Rotated Sorted Array
  • 162. Find Peak Element
  • 852. Peak Index in a Mountain Array
Search on real numbers

Recognize it when: square root, precision, continuous answer.

  • 69. Sqrt(x)
  • 367. Valid Perfect Square
04

Where it is used in real software

Database indexes

B-tree and B+tree indexes in PostgreSQL and MySQL binary search the sorted keys inside each page to find the next child, so a lookup across millions of rows touches only a few pages.

git bisect

Finds the commit that introduced a bug by testing the middle commit and discarding half of the history each time. 1,000 commits need about 10 builds.

Standard libraries

Java Arrays.binarySearch and Collections.binarySearch, C++ std::lower_bound, and Python bisect are all binary search. Java's TreeMap floorKey and ceilingKey answer the same boundary questions.

IP and range lookups

GeoIP and firewall rule tables store sorted IP ranges; a binary search finds the range that contains an address.

Capacity testing

Load tests binary search the request rate to find the highest throughput a service handles within its latency target.

05

Key terms

Search space
The range of indexes still able to contain the answer, usually [low, high].
mid
The index being inspected: low + floor((high - low) / 2).
Invariant
If the target exists, it is always inside [low, high]. Every update must preserve this.
Monotonic predicate
A condition that is false...false then true...true across the search space.
Lower bound
The first index whose value is greater than or equal to the target.
06

How it works, step by step

  1. 1
    Initialize the range

    Set low = 0 and high = n - 1. The whole array is the search space.

  2. 2
    Pick the middle

    Compute mid = low + floor((high - low) / 2). This form avoids integer overflow in languages with fixed-size integers.

  3. 3
    Compare

    If values[mid] equals the target, return mid. The search is complete.

  4. 4
    Discard the left half

    If values[mid] < target, the target can only be to the right, so set low = mid + 1.

  5. 5
    Discard the right half

    If values[mid] > target, the target can only be to the left, so set high = mid - 1.

  6. 6
    Stop when the range is empty

    Loop while low <= high. When low passes high, no candidates remain and the target is absent; return -1. At that moment low is the index where the target would be inserted.

Watch the search space shrink (target = 73)
Step 1 / 5
low
4
0
11
1
18
2
29
3
37
4
51
5
64
6
73
7
82
8
high
96
9

STEP 1The whole array [0, 9] is the search space. If 73 exists, it is between low and high.

07

Search for 73 in 10 sorted values

values = [4, 11, 18, 29, 37, 51, 64, 73, 82, 96], target = 73

Step 1 / 2
Steplowhighmidvalues[mid]Decision
10943737 < 73, so low = 5
25977373 = 73, return 7

NOWStep: 1 | low: 0 | high: 9 | mid: 4 | values[mid]: 37 | Decision: 37 < 73, so low = 5

Only 2 comparisons were needed instead of 8 for a left-to-right scan. Searching for 72 continues: low = 5, high = 6, mid = 5 (51 < 72, low = 6), mid = 6 (64 < 72, low = 7). Now low > high, so the result is -1 and 7 is the insertion position.

08

Implementation

function binarySearch(values: number[], target: number): number {  let low = 0;  let high = values.length - 1;   while (low <= high) {    const mid = low + Math.floor((high - low) / 2);     if (values[mid] === target) return mid;    if (values[mid] < target) {      low = mid + 1;   // target is in the right half    } else {      high = mid - 1;  // target is in the left half    }  }   return -1; // low is the insertion point}
09

Complexity and performance

Time (worst)O(log n)

The range halves every iteration: n, n/2, n/4 ... 1 takes about log2(n) steps.

Time (best)O(1)

The first middle element is the target.

Space (iterative)O(1)

Only low, high, and mid are stored.

Space (recursive)O(log n)

Each halving adds one stack frame.

10

Trade-offs

Requires sorted data

Sorting first costs O(n log n). For a single lookup, a linear scan at O(n) is cheaper; binary search wins when you search the same data many times.

Requires random access

On a linked list, reaching the middle costs O(n), which removes the benefit. Use arrays, or balanced trees for dynamic data.

Inserts are expensive

Keeping an array sorted makes each insert O(n). If data changes often, a balanced BST, skip list, or B-tree provides O(log n) search and update.

Hash maps can be faster

A hash map gives average O(1) exact lookups, but it cannot answer ordered questions such as nearest value, range queries, or lower bound.

11

Variants and related techniques

First and last occurrence

With duplicates, keep searching after a match: move high = mid - 1 to find the first, or low = mid + 1 to find the last, while recording the matched index.

Lower and upper bound

Lower bound finds the first value >= target; upper bound finds the first value > target. Their difference counts occurrences in O(log n).

Search on the answer

When the answer is a number in [lo, hi] and feasible(x) is monotonic, binary search x itself. Examples: minimum eating speed, minimum ship capacity, and split array largest sum.

Rotated sorted array

At least one half around mid is always sorted. Check whether the target lies inside the sorted half, then discard the other half.

Real-number search

For continuous answers such as square roots, loop a fixed number of times (for example 100) or until high - low < epsilon instead of comparing integers.

12

Common mistakes

  • Computing mid as (low + high) / 2 in Java, C, or C++.

    Fix: Use low + (high - low) / 2 so large indexes cannot overflow.

  • Writing low = mid with while (low < high) and floor division.

    Fix: When high = low + 1, mid equals low forever. Use low = mid + 1, or round mid up when low = mid is required.

  • Mixing inclusive [low, high] and half-open [low, high) conventions.

    Fix: Choose one. Inclusive uses high = n - 1, low <= high, high = mid - 1. Half-open uses high = n, low < high, high = mid.

  • Running binary search on unsorted data.

    Fix: The discard rule relies on ordering; verify or sort the input first.

  • Returning any match when the problem asks for the first or last.

    Fix: Continue narrowing after a match and remember the best index found so far.

13

Interview questions

Why is binary search O(log n)?

Each comparison halves the remaining range. After k steps the range size is n / 2^k, which reaches 1 when k = log2(n).

Iterative or recursive: which should you write?

Iterative. It has the same time complexity, uses O(1) space instead of O(log n) stack, and avoids recursion limits.

How do you count occurrences of a value in a sorted array?

Compute upperBound(target) - lowerBound(target). Both are O(log n), so the count is O(log n) regardless of how many duplicates exist.

How can binary search solve an optimization problem?

Turn the question into a feasibility check. If feasible(x) is monotonic, binary search the smallest x where it becomes true. Total cost is O(log(range) * cost of feasible).

Can you binary search a linked list?

Technically yes, but locating mid takes O(n), so the total is O(n). A skip list or balanced tree is the proper ordered structure for linked data.

14

Practice problems

ProblemDifficultyWhat it trains
Binary SearchEasyWrite the classic inclusive loop from memory.
Search Insert PositionEasyReturn low after the loop: the lower bound.
First Bad VersionEasyBinary search over a monotonic predicate.
Find First and Last Position of ElementMediumLower and upper bound on duplicates.
Search in Rotated Sorted ArrayMediumIdentify the sorted half each step.
Koko Eating BananasMediumBinary search on the answer.
Capacity To Ship Packages Within D DaysMediumFeasibility function plus binary search.
Median of Two Sorted ArraysHardBinary search on a partition index.