Interview Concept: Lower Bound vs Upper Bound Binary Search

Lower bound vs upper bound binary search explained: first index >= target vs first index > target, with ready templates in Python, Java and C++.

Overview

Most binary-search bugs come from fuzzy boundaries. Two precise templates remove the guesswork: lower bound (first index whose value is >= target) and upper bound (first index whose value is > target). Learn these two and most variants fall out.

Lower Bound (first value >= target)

Python

def lower_bound(nums, target):
    lo, hi = 0, len(nums)
    while lo < hi:
        mid = (lo + hi) // 2
        if nums[mid] < target:
            lo = mid + 1
        else:
            hi = mid
    return lo

Java

int lowerBound(int[] nums, int target) {
    int lo = 0, hi = nums.length;
    while (lo < hi) {
        int mid = lo + (hi - lo) / 2;
        if (nums[mid] < target) lo = mid + 1;
        else hi = mid;
    }
    return lo;
}

C++

int lowerBound(vector<int>& nums, int target) {
    int lo = 0, hi = (int)nums.size();
    while (lo < hi) {
        int mid = lo + (hi - lo) / 2;
        if (nums[mid] < target) lo = mid + 1;
        else hi = mid;
    }
    return lo;   // same as std::lower_bound
}

Upper Bound (first value > target)

Python

def upper_bound(nums, target):
    lo, hi = 0, len(nums)
    while lo < hi:
        mid = (lo + hi) // 2
        if nums[mid] <= target:
            lo = mid + 1
        else:
            hi = mid
    return lo

Java

int upperBound(int[] nums, int target) {
    int lo = 0, hi = nums.length;
    while (lo < hi) {
        int mid = lo + (hi - lo) / 2;
        if (nums[mid] <= target) lo = mid + 1;
        else hi = mid;
    }
    return lo;
}

C++

int upperBound(vector<int>& nums, int target) {
    int lo = 0, hi = (int)nums.size();
    while (lo < hi) {
        int mid = lo + (hi - lo) / 2;
        if (nums[mid] <= target) lo = mid + 1;
        else hi = mid;
    }
    return lo;   // same as std::upper_bound
}

What You Can Build From Them

  • Count of a value = upper_bound - lower_bound.
  • First/last position = lower_bound(target) and upper_bound(target) - 1.
  • Exists? check i = lower_bound; i < n and nums[i] == target.
  • The only difference between the two templates is < versus <=.

Key Takeaways

  • Use the half-open window [lo, hi) with hi = n to avoid off-by-one bugs.
  • Lower bound uses nums[mid] < target; upper bound uses nums[mid] <= target.
  • Reference: C++ std::lower_bound / std::upper_bound; Python bisect_left / bisect_right.
Written by Lorens Mishra

Software Engineer Notes Management System Administrator

Discussion

0 comments
Sign in to join the discussion.

No comments yet. Be the first to say something.