Skip to content

Lower Bound

Find the first position where a value can be inserted without violating sorted order.

Lower bound finds the first index at which a value xx can be inserted in a sorted array while preserving order. It returns the smallest index ii such that

A[i]x A[i] \ge x

If all elements are smaller than xx, it returns nn.

This operation forms the basis of many ordered data structure queries, including range queries and duplicate handling.

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] \ge x

Return nn if no such index exists.

Key Idea

The predicate

A[i]x A[i] \ge x

is monotone:

  • false for small indices
  • true for large indices

Binary search can locate the first true position.

Algorithm

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

lower_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 left
20213move left
30101move right

Return index 11.

Interpretation

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

This partitions the array.

Correctness

Invariant:

  • The answer always lies in [l,r)[l, r)

Each step reduces the interval while preserving:

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

When l=rl = r, the first true index has been isolated.

Complexity

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

Space:

O(1) O(1)

Use Cases

  • Insert position in sorted array
  • Count elements less than xx
  • Range queries: combine with upper bound
  • Deduplication boundaries

Implementation

def lower_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 LowerBound(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
}