DSA · Lesson 5 of 17

Binary Search

⏱ 16 min🎬 Interactive visualizer💻 Python · Java · C++ · JavaScript🧩 6 practice problems

Halve the search space each step for O(log n). Works on sorted arrays and, more powerfully, on any monotonic yes/no question about the answer.

The idea

If the data is sorted, compare with the middle element and throw away the half that cannot contain the answer. A billion elements need only about 30 comparisons.

Three templates worth memorising

  1. Exact match: while lo <= hi, return on equality.
  2. Lower bound (first index with a[i] >= x): half-open range [lo, hi), while lo < hi, set hi = mid when a[mid] >= x. This gives insertion positions, first and last occurrences, and LIS in O(n log n).
  3. Binary search on the answer: when “can we do it with value k?” is monotonic (false … false, true … true), binary-search the smallest k that works. Examples: Koko eating bananas, ship packages within D days, split array largest sum, minimum time to finish tasks.

Recognise it

Code template

# 1) Exact match
def search(a, x):
    lo, hi = 0, len(a) - 1
    while lo <= hi:
        mid = (lo + hi) // 2
        if a[mid] == x: return mid
        if a[mid] < x: lo = mid + 1
        else: hi = mid - 1
    return -1

# 2) Lower bound: first index with a[i] >= x
def lower_bound(a, x):
    lo, hi = 0, len(a)
    while lo < hi:
        mid = (lo + hi) // 2
        if a[mid] < x: lo = mid + 1
        else: hi = mid
    return lo

# 3) Binary search on the answer
def smallest_ok(lo, hi, ok):        # ok(k) is False...False, True...True
    while lo < hi:
        mid = (lo + hi) // 2
        if ok(mid): hi = mid
        else: lo = mid + 1
    return lo
// 1) Exact match
int search(int[] a, int x) {
    int lo = 0, hi = a.length - 1;
    while (lo <= hi) {
        int mid = lo + (hi - lo) / 2;
        if (a[mid] == x) return mid;
        if (a[mid] < x) lo = mid + 1; else hi = mid - 1;
    }
    return -1;
}

// 2) Lower bound: first index with a[i] >= x
int lowerBound(int[] a, int x) {
    int lo = 0, hi = a.length;
    while (lo < hi) { int mid = lo + (hi - lo) / 2; if (a[mid] < x) lo = mid + 1; else hi = mid; }
    return lo;
}

// 3) Binary search on the answer
int smallestOk(int lo, int hi, java.util.function.IntPredicate ok) {
    while (lo < hi) { int mid = lo + (hi - lo) / 2; if (ok.test(mid)) hi = mid; else lo = mid + 1; }
    return lo;
}
// 1) Exact match
int search(const vector<int>& a, int x) {
    int lo = 0, hi = (int)a.size() - 1;
    while (lo <= hi) {
        int mid = lo + (hi - lo) / 2;
        if (a[mid] == x) return mid;
        if (a[mid] < x) lo = mid + 1; else hi = mid - 1;
    }
    return -1;
}

// 2) Lower bound: std::lower_bound does exactly this
int lowerBound(const vector<int>& a, int x) { return lower_bound(a.begin(), a.end(), x) - a.begin(); }

// 3) Binary search on the answer
template <class F> long long smallestOk(long long lo, long long hi, F ok) {
    while (lo < hi) { long long mid = lo + (hi - lo) / 2; if (ok(mid)) hi = mid; else lo = mid + 1; }
    return lo;
}
// 1) Exact match
function search(a, x) {
  let lo = 0, hi = a.length - 1;
  while (lo <= hi) {
    const mid = (lo + hi) >> 1;
    if (a[mid] === x) return mid;
    if (a[mid] < x) lo = mid + 1; else hi = mid - 1;
  }
  return -1;
}

// 2) Lower bound: first index with a[i] >= x
function lowerBound(a, x) {
  let lo = 0, hi = a.length;
  while (lo < hi) { const mid = (lo + hi) >> 1; if (a[mid] < x) lo = mid + 1; else hi = mid; }
  return lo;
}

// 3) Binary search on the answer
function smallestOk(lo, hi, ok) {
  while (lo < hi) { const mid = Math.floor((lo + hi) / 2); if (ok(mid)) hi = mid; else lo = mid + 1; }
  return lo;
}

Complexity

O(log n) for a search. Binary search on the answer is O(log V × cost of one feasibility check), often O(n log V).

Practise this pattern (6 problems)

Each problem has a statement, hints, approaches, solutions in 4 languages and a code runner. Solve them in order: easy first.

Common mistakes

Check yourself: what is the first value Koko’s speed search tries for piles [3, 6, 7, 11]? lo = 1, hi = 11, so mid = 6. At speed 6 she needs 1 + 1 + 2 + 2 = 6 hours.
Created by Ajeetkumar