Skip to content
intermediate Phase 3 · Sorting & Searching

Binary Search

Master binary search on sorted arrays and its variants for efficient searching.

1h 15m
7 problems
Topic Progress 0%

Binary Search Fundamentals

Binary search is a divide-and-conquer algorithm that finds an element in a sorted array by repeatedly halving the search space.

How It Works

  1. Compare target with middle element
  2. If target equals middle → found
  3. If target < middle → search left half
  4. If target > middle → search right half
  5. Repeat until found or search space is empty

Visual Example

Sorted Array: [2, 5, 8, 12, 16, 23, 38, 56, 72, 91]
Target: 23

Step 1: low=0, high=9, mid=4 → arr[4]=16 < 23 → search right
Step 2: low=5, high=9, mid=7 → arr[7]=56 > 23 → search left
Step 3: low=5, high=6, mid=5 → arr[5]=23 = 23 → FOUND!

Iterative Implementation (Preferred)

public int binarySearch(int[] arr, int target) {
    int low = 0;
    int high = arr.length - 1;
    
    while (low <= high) {
        int mid = low + (high - low) / 2;  // Prevents overflow
        
        if (arr[mid] == target) {
            return mid;  // Found
        } else if (arr[mid] < target) {
            low = mid + 1;  // Search right half
        } else {
            high = mid - 1;  // Search left half
        }
    }
    
    return -1;  // Not found
}

Recursive Implementation

public int binarySearchRecursive(int[] arr, int target, int low, int high) {
    if (low > high) {
        return -1;  // Base case: not found
    }
    
    int mid = low + (high - low) / 2;
    
    if (arr[mid] == target) {
        return mid;
    } else if (arr[mid] < target) {
        return binarySearchRecursive(arr, target, mid + 1, high);
    } else {
        return binarySearchRecursive(arr, target, low, mid - 1);
    }
}

Why low + (high - low) / 2?

// WRONG: Can cause integer overflow
int mid = (low + high) / 2;
// If low = 1,000,000,000 and high = 2,000,000,000
// low + high = 3,000,000,000 > Integer.MAX_VALUE

// CORRECT: Prevents overflow
int mid = low + (high - low) / 2;
// Equivalent to low + (high - low) / 2
// Both expressions give same result, but second is safe

Complexity Analysis

Aspect Complexity
Time (best) O(1) - found at middle
Time (worst) O(log n) - search space halved each step
Time (average) O(log n)
Space (iterative) O(1)
Space (recursive) O(log n) - call stack

Binary Search Variations

Variation 1: Finding First Occurrence

Useful when array has duplicates.

public int findFirst(int[] arr, int target) {
    int low = 0, high = arr.length - 1;
    int result = -1;
    
    while (low <= high) {
        int mid = low + (high - low) / 2;
        
        if (arr[mid] == target) {
            result = mid;      // Record position
            high = mid - 1;    // Continue searching left
        } else if (arr[mid] < target) {
            low = mid + 1;
        } else {
            high = mid - 1;
        }
    }
    
    return result;
}

Variation 2: Finding Last Occurrence

public int findLast(int[] arr, int target) {
    int low = 0, high = arr.length - 1;
    int result = -1;
    
    while (low <= high) {
        int mid = low + (high - low) / 2;
        
        if (arr[mid] == target) {
            result = mid;      // Record position
            low = mid + 1;     // Continue searching right
        } else if (arr[mid] < target) {
            low = mid + 1;
        } else {
            high = mid - 1;
        }
    }
    
    return result;
}

Variation 3: Finding Floor and Ceil

Floor: Largest element ≤ target
Ceil: Smallest element ≥ target

// Floor - largest element <= target
public int findFloor(int[] arr, int target) {
    int low = 0, high = arr.length - 1;
    int result = -1;
    
    while (low <= high) {
        int mid = low + (high - low) / 2;
        
        if (arr[mid] <= target) {
            result = arr[mid];
            low = mid + 1;
        } else {
            high = mid - 1;
        }
    }
    
    return result;
}

// Ceil - smallest element >= target
public int findCeil(int[] arr, int target) {
    int low = 0, high = arr.length - 1;
    int result = -1;
    
    while (low <= high) {
        int mid = low + (high - low) / 2;
        
        if (arr[mid] >= target) {
            result = arr[mid];
            high = mid - 1;
        } else {
            low = mid + 1;
        }
    }
    
    return result;
}

When to Use Binary Search

  1. Sorted array - classic binary search
  2. Monotonic function - function that only increases or decreases
  3. Search space is ordered - can eliminate half each step
  4. Finding minimum/maximum with constraint - binary search on answer

Common Mistakes

  1. Off-by-one errors - low <= high vs low < high
  2. Integer overflow - use low + (high - low) / 2
  3. Infinite loops - ensure low and high always change
  4. Wrong midpoint calculation - always use safe formula

Interactive Visualization

Binary Search Visualization

Press Play or Step to begin
Current Found / Done Eliminated Unvisited

Practice Problems

0 / 3 solved
Search in Rotated Sorted Array
Modified Binary Search

Given a rotated sorted array and a target value, return its index.

Example:

Input: nums = [4,5,6,7,0,1,2], target = 0

Output: 4

Array rotated at index 3. Target 0 at index 4.

Edge Cases:

  • Single element — match or return -1
  • Target not in array
  • Array not rotated (same as sorted)
  • Rotation at boundary — last element is minimum
  • Target is the pivot element
Find Minimum in Rotated Sorted Array
Binary Search - Pivot

Given a rotated sorted array, find the minimum element.

Example:

Input: nums = [3,4,5,1,2]

Output: 1

Minimum is 1 at index 3.

Edge Cases:

  • Not rotated (already sorted): first element is minimum
  • Single element: return that element
  • Two elements: return min of both
Search a 2D Matrix
Binary Search on Flattened

Write an efficient algorithm that searches for a value in an m x n matrix. Each row is sorted and the first integer of each row is greater than the last integer of the previous row.

Example:

Input: matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3

Output: true

3 is found in the matrix.

Optimal Solution — O(log(m*n)) time, O(1) space

Binary search treating matrix as 1D array

class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int m = matrix.length, n = matrix[0].length;
        int low = 0, high = m * n - 1;
        while (low <= high) {
            int mid = low + (high - low) / 2;
            int val = matrix[mid / n][mid % n];
            if (val == target) return true;
            else if (val < target) low = mid + 1;
            else high = mid - 1;
        }
        return false;
    }
}

Edge Cases:

  • Single element matrix
  • Target at corners
  • Target not found

Quiz

1. What is the time complexity of binary search?

Question 1 options

2. Why should you use `low + (high - low) / 2` instead of `(low + high) / 2`?

Question 2 options

3. What is a common mistake when implementing Binary Search?

Question 3 options

Flashcards

Question

What is the time complexity of binary search?

Answer

O(log n) - the search space is halved with each comparison.

Question

When can you apply binary search?

Answer

When the search space is ordered or you have a monotonic function that divides the space into valid/invalid regions.

Question

Binary Search best practices

Answer

Follow SOLID principles, write clean code, test thoroughly, document decisions, and monitor in production.

Revision Notes

Key Takeaways

  • 1. Binary search requires sorted data or monotonic function
  • 2. Use safe midpoint formula to prevent integer overflow
  • 3. Iterative approach is preferred (O(1) space)
  • 4. Apply to rotated arrays by determining which half is sorted

Interview Tips

  • Clarify if array is sorted before applying binary search
  • Ask about duplicates - affects first/last occurrence approach
  • Discuss edge cases: empty array, single element, target not found
  • Mention time complexity advantage over linear search

Cheat Sheet

Binary Search Cheat Sheet

Template:

int low = 0, high = n - 1;
while (low <= high) {
    int mid = low + (high - low) / 2;
    if (arr[mid] == target) return mid;
    else if (arr[mid] < target) low = mid + 1;
    else high = mid - 1;
}

Variations:

  • First occurrence: move high = mid - 1 when found
  • Last occurrence: move low = mid + 1 when found
  • Floor/Ceil: track result before narrowing

Key Points:

  • Always use low + (high - low) / 2 for overflow safety
  • Array must be sorted (or function must be monotonic)
  • O(log n) time, O(1) space (iterative)