Abstracting Binary Search for Monotonic Function Boundaries

Binary search extends far beyond locating values in sorted arrays. The core requirement for applying this technique is identifying a monotonic relationship between an independent variable and a computed result. When a problem can be modeled as finding an input x such that a monotonic function f(x) equals a specific target, binary search becomes applicable.

Most practical algorithmic challenges require finding boundary values rather than exact matches. Optimization problems asking for minimum capacity, maximum speed, or earliest time inherently translate to searching for the leftmost or rightmost valid x that satisfies a condition.

Left Boundary Search Pattern

When the objective is to find the smallest x where f(x) >= target (or exactly equals it in a discrete domain), the search space must contract from the right upon finding a valid candidate.

int findLeftBoundary(const std::vector<int>& data, int goal) {
    if (data.empty()) return -1;
    int low = 0;
    int high = data.size();

    while (low < high) {
        int pivot = low + ((high - low) >> 1);
        int val = data[pivot];

        if (val == goal) {
            high = pivot;
        } else if (val < goal) {
            low = pivot + 1;
        } else {
            high = pivot;
        }
    }
    return low;
}

Right Boundary Search Pattern

Conversely, locating the largest valid x requires pushing the lower bound upward when a match occurs, effectively searching for the insertion point immediately after the last valid element.

int findRightBoundary(const std::vector<int>& data, int goal) {
    if (data.empty()) return -1;
    int low = 0;
    int high = data.size();

    while (low < high) {
        int pivot = low + ((high - low) >> 1);
        int val = data[pivot];

        if (val == goal) {
            low = pivot + 1;
        } else if (val < goal) {
            low = pivot + 1;
        } else {
            high = pivot;
        }
    }
    return low - 1;
}

Abstracting the Monotonic Function

The array index serves as the independent variable x, and array access acts as the function f(x) = data[x]. Since the array is sorted, f(x) is strictly monotonic. The problem of finding the first occurrence of goal translates to finding the minimum x where f(x) == goal.

This abstraction unlocks binary search for non-array problems. Any scenario where increasing x consistently increases or decreases a computed metric f(x) fits this model. The algorithm searches the domain of x rather than a physical data structure.

int evaluate(int x) {
    // Compute metric based on x
    // Must be strictly monotonic (increasing or decreasing)
    return computed_value;
}

int solveBoundary(int min_x, int max_x, int goal) {
    int low = min_x;
    int high = max_x + 1;

    while (low < high) {
        int pivot = low + ((high - low) >> 1);
        int result = evaluate(pivot);

        if (result == goal) {
            high = pivot; // Adjust to low = pivot + 1 for right boundary
        } else if (result < goal) {
            low = pivot + 1;
        } else {
            high = pivot;
        }
    }
    return low;
}

Systematic Application Framework

Implementing binary search for complex constraints follows a deterministic sequence:

  1. Identify Variables: Isolate the independent variable x, define the monotonic mapping f(x), and establish the target constraint. Implement f(x) as a standalone function or lambda.
  2. Define Search Space: Determine the absolute minimum and maximum possible values for x. Initialize low and high to cover this inclusive range, typically setting high to max_x + 1 for half-open interval logic.
  3. Select Boundary Logic: Decide whether the problem requires the smallest valid x (left boundary) or largest valid x (right boundary). Adjust the low and high pointers inside the loop accordingly, ensuring the loop terminates when low == high.

Tags: algorithms binary-search monotonic-functions competitive-programming Optimization

Posted on Sat, 09 May 2026 17:30:22 +0000 by twister47