0

Binary search — O(log n) lookups on sorted data

Intermediate5 min read·eng-08-003
interview

Concept

Binary search finds a target in a sorted array in O(log n) time. Each step eliminates half the remaining candidates.

How it works:

  1. Compute mid = (left + right) / 2.
  2. If arr[mid] === target, return mid.
  3. If arr[mid] < target, the target must be in the right half: left = mid + 1.
  4. If arr[mid] > target, the target must be in the left half: right = mid - 1.
  5. Repeat until left > right (not found).

Pre-condition: The array MUST be sorted. Binary search returns undefined behavior on unsorted data.

O(log n) intuition: 1 billion elements → at most 30 steps (log₂ 1,000,000,000 ≈ 30).

Common variants:

  • Find exact target: Standard binary search.
  • Find leftmost position of target (first occurrence): When arr[mid] === target, don't return — continue left (right = mid - 1), record the position.
  • Find rightmost position: When arr[mid] === target, continue right (left = mid + 1), record the position.
  • Find insertion point: Where would target be inserted to keep array sorted?

PHP built-in: PHP has no built-in binary search. array_search() is O(n). Sort with sort() then use binary search.

Database relevance: B-tree indexes in databases are a generalization of binary search — each node can have many children, and the tree stays balanced. Finding a row by indexed column is O(log n) — this is why indexes make queries fast.

Code Example

php
<?php
// Basic binary search — returns index or -1
function binarySearch(array $sorted, int $target): int
{
    $left  = 0;
    $right = count($sorted) - 1;

    while ($left <= $right) {
        $mid = intdiv($left + $right, 2); // avoids overflow vs ($left + $right) / 2

        if ($sorted[$mid] === $target) return $mid;
        if ($sorted[$mid] < $target)   $left  = $mid + 1;
        else                           $right = $mid - 1;
    }
    return -1;
}

$arr    = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19];
$index  = binarySearch($arr, 13); // 6
$notFound = binarySearch($arr, 8); // -1

// Find first occurrence of target (leftmost)
function searchFirst(array $sorted, int $target): int
{
    $left = 0; $right = count($sorted) - 1; $result = -1;
    while ($left <= $right) {
        $mid = intdiv($left + $right, 2);
        if ($sorted[$mid] === $target) { $result = $mid; $right = $mid - 1; } // go left!
        elseif ($sorted[$mid] < $target) $left = $mid + 1;
        else                             $right = $mid - 1;
    }
    return $result;
}

// Find insertion point (where target WOULD go to maintain sort order)
function searchInsertionPoint(array $sorted, int $target): int
{
    $left = 0; $right = count($sorted);
    while ($left < $right) {
        $mid = intdiv($left + $right, 2);
        if ($sorted[$mid] < $target) $left  = $mid + 1;
        else                          $right = $mid;
    }
    return $left; // left is the insertion index
}

// Search in rotated sorted array (classic interview problem)
// [4, 5, 6, 7, 0, 1, 2] — rotated at index 4
function searchRotated(array $arr, int $target): int
{
    $left = 0; $right = count($arr) - 1;
    while ($left <= $right) {
        $mid = intdiv($left + $right, 2);
        if ($arr[$mid] === $target) return $mid;

        if ($arr[$left] <= $arr[$mid]) { // left half is sorted
            if ($arr[$left] <= $target && $target < $arr[$mid]) $right = $mid - 1;
            else                                                  $left  = $mid + 1;
        } else {                          // right half is sorted
            if ($arr[$mid] < $target && $target <= $arr[$right]) $left  = $mid + 1;
            else                                                   $right = $mid - 1;
        }
    }
    return -1;
}

echo searchRotated([4, 5, 6, 7, 0, 1, 2], 0); // 4
echo searchRotated([4, 5, 6, 7, 0, 1, 2], 3); // -1

// Real-world: binary search on sorted DB result
// SELECT id FROM products ORDER BY price ASC;
// Then binary search to find the first product over $50 — O(log n)