Binary Search Algorithm - Complete Guide

Binary search is one of the most fundamental algorithms in computer science. It efficiently finds elements in sorted arrays with O(log n) time complexity.

Binary search is a divide-and-conquer algorithm that finds the position of a target value within a sorted array by repeatedly dividing the search interval in half.

How Binary Search Works #

  1. Start with the middle element
  2. If target equals middle, return the index
  3. If target is less than middle, search the left half
  4. If target is greater than middle, search the right half
  5. Repeat until target is found or interval is empty

Visual Example #

Array: [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
Target: 13

Step 1: Check middle (9)
[1, 3, 5, 7, 9, | 11, 13, 15, 17, 19]
13 > 9, search right half

Step 2: Check middle of right half (15)
[11, 13, 15, 17, 19]
      ^
13 < 15, search left half

Step 3: Check middle of left half (13)
[11, 13]
     ^
Found! Return index 6

Basic Implementation #

Iterative Approach #

function binarySearch(arr, target) {
  let left = 0;
  let right = arr.length - 1;

  while (left <= right) {
    const mid = Math.floor((left + right) / 2);

    if (arr[mid] === target) {
      return mid;  // Found
    } else if (arr[mid] < target) {
      left = mid + 1;  // Search right half
    } else {
      right = mid - 1;  // Search left half
    }
  }

  return -1;  // Not found
}

const arr = [1, 3, 5, 7, 9, 11, 13, 15];
console.log(binarySearch(arr, 7));  // 3
console.log(binarySearch(arr, 99));  // -1

Recursive Approach #

function binarySearchRecursive(arr, target, left = 0, right = arr.length - 1) {
  if (left > right) {
    return -1;  // Not found
  }

  const mid = Math.floor((left + right) / 2);

  if (arr[mid] === target) {
    return mid;
  } else if (arr[mid] < target) {
    return binarySearchRecursive(arr, target, mid + 1, right);
  } else {
    return binarySearchRecursive(arr, target, left, mid - 1);
  }
}

const arr = [1, 3, 5, 7, 9, 11, 13, 15];
console.log(binarySearchRecursive(arr, 9));  // 4

Avoiding Integer Overflow #

In some languages, (left + right) / 2 can cause overflow. Use this instead:

// Better
const mid = left + Math.floor((right - left) / 2);

// Or using bit shift
const mid = (left + right) >>> 1;

Binary Search Variants #

Find First Occurrence #

function findFirst(arr, target) {
  let left = 0;
  let right = arr.length - 1;
  let result = -1;

  while (left <= right) {
    const mid = Math.floor((left + right) / 2);

    if (arr[mid] === target) {
      result = mid;
      right = mid - 1;  // Continue searching left
    } else if (arr[mid] < target) {
      left = mid + 1;
    } else {
      right = mid - 1;
    }
  }

  return result;
}

const arr = [1, 2, 2, 2, 3, 4, 5];
console.log(findFirst(arr, 2));  // 1

Find Last Occurrence #

function findLast(arr, target) {
  let left = 0;
  let right = arr.length - 1;
  let result = -1;

  while (left <= right) {
    const mid = Math.floor((left + right) / 2);

    if (arr[mid] === target) {
      result = mid;
      left = mid + 1;  // Continue searching right
    } else if (arr[mid] < target) {
      left = mid + 1;
    } else {
      right = mid - 1;
    }
  }

  return result;
}

const arr = [1, 2, 2, 2, 3, 4, 5];
console.log(findLast(arr, 2));  // 3

Find Insert Position #

function searchInsert(arr, target) {
  let left = 0;
  let right = arr.length - 1;

  while (left <= right) {
    const mid = Math.floor((left + right) / 2);

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

  return left;  // Insert position
}

const arr = [1, 3, 5, 6];
console.log(searchInsert(arr, 5));  // 2
console.log(searchInsert(arr, 2));  // 1
console.log(searchInsert(arr, 7));  // 4

Find Peak Element #

function findPeakElement(arr) {
  let left = 0;
  let right = arr.length - 1;

  while (left < right) {
    const mid = Math.floor((left + right) / 2);

    if (arr[mid] > arr[mid + 1]) {
      right = mid;  // Peak in left half or mid
    } else {
      left = mid + 1;  // Peak in right half
    }
  }

  return left;
}

const arr = [1, 2, 3, 1];
console.log(findPeakElement(arr));  // 2 (value 3)

Advanced Binary Search Problems #

Search in Rotated Sorted Array #

function searchRotated(arr, target) {
  let left = 0;
  let right = arr.length - 1;

  while (left <= right) {
    const mid = Math.floor((left + right) / 2);

    if (arr[mid] === target) {
      return mid;
    }

    // Determine which half is sorted
    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;
}

const arr = [4, 5, 6, 7, 0, 1, 2];
console.log(searchRotated(arr, 0));  // 4
console.log(searchRotated(arr, 3));  // -1

Find Minimum in Rotated Sorted Array #

function findMin(arr) {
  let left = 0;
  let right = arr.length - 1;

  while (left < right) {
    const mid = Math.floor((left + right) / 2);

    if (arr[mid] > arr[right]) {
      // Minimum is in right half
      left = mid + 1;
    } else {
      // Minimum is in left half or mid
      right = mid;
    }
  }

  return arr[left];
}

const arr = [4, 5, 6, 7, 0, 1, 2];
console.log(findMin(arr));  // 0

Search 2D Matrix #

function searchMatrix(matrix, target) {
  if (!matrix.length || !matrix[0].length) return false;

  const rows = matrix.length;
  const cols = matrix[0].length;
  let left = 0;
  let right = rows * cols - 1;

  while (left <= right) {
    const mid = Math.floor((left + right) / 2);
    const row = Math.floor(mid / cols);
    const col = mid % cols;
    const value = matrix[row][col];

    if (value === target) {
      return true;
    } else if (value < target) {
      left = mid + 1;
    } else {
      right = mid - 1;
    }
  }

  return false;
}

const matrix = [
  [1,  3,  5,  7],
  [10, 11, 16, 20],
  [23, 30, 34, 60]
];
console.log(searchMatrix(matrix, 3));  // true
console.log(searchMatrix(matrix, 13));  // false

Find Square Root #

function mySqrt(x) {
  if (x < 2) return x;

  let left = 1;
  let right = Math.floor(x / 2);

  while (left <= right) {
    const mid = Math.floor((left + right) / 2);
    const square = mid * mid;

    if (square === x) {
      return mid;
    } else if (square < x) {
      left = mid + 1;
    } else {
      right = mid - 1;
    }
  }

  return right;  // Floor of square root
}

console.log(mySqrt(4));  // 2
console.log(mySqrt(8));  // 2
console.log(mySqrt(16));  // 4

Koko Eating Bananas #

function minEatingSpeed(piles, h) {
  let left = 1;
  let right = Math.max(...piles);

  function canFinish(speed) {
    let hours = 0;
    for (const pile of piles) {
      hours += Math.ceil(pile / speed);
    }
    return hours <= h;
  }

  while (left < right) {
    const mid = Math.floor((left + right) / 2);

    if (canFinish(mid)) {
      right = mid;  // Try slower
    } else {
      left = mid + 1;  // Must be faster
    }
  }

  return left;
}

console.log(minEatingSpeed([3, 6, 7, 11], 8));  // 4
console.log(minEatingSpeed([30, 11, 23, 4, 20], 5));  // 30

Capacity to Ship Packages #

function shipWithinDays(weights, days) {
  let left = Math.max(...weights);
  let right = weights.reduce((sum, w) => sum + w, 0);

  function canShip(capacity) {
    let daysNeeded = 1;
    let currentLoad = 0;

    for (const weight of weights) {
      if (currentLoad + weight > capacity) {
        daysNeeded++;
        currentLoad = 0;
      }
      currentLoad += weight;
    }

    return daysNeeded <= days;
  }

  while (left < right) {
    const mid = Math.floor((left + right) / 2);

    if (canShip(mid)) {
      right = mid;
    } else {
      left = mid + 1;
    }
  }

  return left;
}

console.log(shipWithinDays([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 5));  // 15

Binary Search Template #

Standard Template #

function binarySearch(arr, target) {
  let left = 0;
  let right = arr.length - 1;

  while (left <= right) {
    const mid = left + Math.floor((right - left) / 2);

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

  return -1;
}

Left Bound Template #

function leftBound(arr, target) {
  let left = 0;
  let right = arr.length;

  while (left < right) {
    const mid = left + Math.floor((right - left) / 2);

    if (arr[mid] < target) {
      left = mid + 1;
    } else {
      right = mid;
    }
  }

  return left;
}

Right Bound Template #

function rightBound(arr, target) {
  let left = 0;
  let right = arr.length;

  while (left < right) {
    const mid = left + Math.floor((right - left) / 2);

    if (arr[mid] <= target) {
      left = mid + 1;
    } else {
      right = mid;
    }
  }

  return left - 1;
}

Time and Space Complexity #

AspectComplexity
Time (Average)O(log n)
Time (Worst)O(log n)
Space (Iterative)O(1)
Space (Recursive)O(log n)
Array SizeLinear SearchBinary Search
1010 operations4 operations
100100 operations7 operations
1,0001,000 operations10 operations
1,000,0001,000,000 operations20 operations

Use binary search when:

  • Data is sorted
  • Need O(log n) time complexity
  • Random access is available (arrays)
  • Data set is large

Don’t use binary search when:

  • Data is unsorted (sorting cost O(n log n))
  • Data structure is linked list
  • Data set is very small (linear is simpler)

Common Mistakes #

  1. Wrong loop condition - Use left <= right or left < right correctly
  2. Integer overflow - Use left + (right - left) / 2
  3. Off-by-one errors - Careful with mid + 1 and mid - 1
  4. Unsorted array - Binary search only works on sorted data
  5. Infinite loops - Ensure left/right pointers always progress

Tips for Binary Search Problems #

  1. Identify the search space - What are we searching over?
  2. Define the condition - What makes an answer valid?
  3. Choose the template - Standard, left bound, or right bound?
  4. Handle edge cases - Empty array, single element, not found
  5. Test with examples - Walk through small cases

Binary search is essential for technical interviews and real-world applications. Master the template and common variations to solve problems efficiently.