Skip to content

Upper Bound

Find the first index where elements become strictly greater than a given value.

Upper bound finds the first index at which elements become strictly greater than a value xx. It returns the smallest index ii such that

A[i]>x A[i] > x

If no such index exists, it returns nn.

This operation complements lower bound and allows precise range queries over equal values.

Problem

Given a sorted array AA of length nn and a value xx, find the smallest index ii such that

A[i]>x A[i] > x

Return nn if all elements are x\le x.

Key Idea

The predicate

A[i]>x A[i] > x

is monotone:

  • false for smaller indices
  • true for larger indices

Binary search isolates the first true position.

Algorithm

Use a half-open interval [l,r)[l, r).

upper_bound(A, x):
    l = 0
    r = length(A)

    while l < r:
        m = l + (r - l) // 2

        if A[m] <= x:
            l = m + 1
        else:
            r = m

    return l

Example

Let

A=[1,3,3,5,7] A = [1, 3, 3, 5, 7]

and

x=3 x = 3

Steps:

steplrmA[m]action
10523move right
23547move left
33435move left

Return index 33.

Interpretation

  • All indices <i< i satisfy A[j]xA[j] \le x
  • All indices i\ge i satisfy A[j]>xA[j] > x

This splits the array into two regions.

Relation to Lower Bound

operationconditionmeaning
lower boundA[i]xA[i] \ge xfirst occurrence of xx or insertion point
upper boundA[i]>xA[i] > xposition after last occurrence of xx

Range of equal elements:

[lower_bound(x),upper_bound(x)) [\text{lower\_bound}(x), \text{upper\_bound}(x))

Correctness

Invariant:

  • The answer remains in [l,r)[l, r)

Each step eliminates half the interval while preserving:

  • left side contains only false values
  • right side contains possible true values

Termination at l=rl = r yields the first true index.

Complexity

casetime
all casesO(logn)O(\log n)

Space:

O(1) O(1)

Use Cases

  • Count elements x\le x
  • Find right boundary of duplicates
  • Range counting and interval queries
  • Partitioning sorted data

Implementation

def upper_bound(a, x):
    l, r = 0, len(a)
    while l < r:
        m = l + (r - l) // 2
        if a[m] <= x:
            l = m + 1
        else:
            r = m
    return l
func UpperBound(a []int, x int) int {
    l, r := 0, len(a)
    for l < r {
        m := l + (r-l)/2
        if a[m] <= x {
            l = m + 1
        } else {
            r = m
        }
    }
    return l
}