Implement Upper Bound

easy

You are given a sorted (non-decreasing) array arr and a number target. Return the upper bound of target — the smallest index i such that arr[i] > target (strictly greater).

If every element of arr is less than or equal to target, there is no such index inside the array — return arr.length, one past the last position.

Put differently: every element at indices 0 … i-1 is at most target, and arr[i] (if it exists) is the first element that beats it. Duplicates of target do not count — the bound lands after the last copy.

Hints

The array is sorted. Do you really need to look at every element to find where values stop being small enough?
You are hunting a boundary: everything at most target sits on the left, everything greater sits on the right. You want the first index of the right part — and remember, equal values belong to the left part.
Binary search on the boundary: if arr[mid] > target, record mid as a candidate and search left; otherwise search right. Initialise the answer to arr.length so the no-greater-element case works for free.

Common doubts

Lower bound is the first index with arr[i] >= target (equal counts); upper bound is the first index with arr[i] > target (strictly greater). If target appears in the array, lower bound points at its first copy and upper bound points just past its last copy. If target is absent, the two are equal.
The upper bound is really an insert position: the spot where you could insert something just bigger than target and keep the array sorted. When every element is at most target, that spot is one past the end — index arr.length.
The comparison is strict, so every copy of target fails arr[mid] > target and pushes the search right. The bound naturally lands after the last duplicate — no special casing needed.

Interview follow-ups

Compute upperBound(target) - lowerBound(target) — two binary searches bracket the run of equal values, giving the count in O(log n) without ever scanning it.
Same skeleton, different condition. Lower bound: record and go left when arr[mid] >= target. Ceil is the value at the lower bound index; floor is the last index with arr[i] <= target, which is upperBound(target) - 1.
The boundary flips sides: the strictly-greater elements form a prefix. Mirror the comparisons — when arr[mid] > target, record and search right instead of left.

Fun facts

  • upperBound(x) - lowerBound(x) counts the occurrences of x in a sorted array in O(log n) — the two bounds bracket every run of equal keys, a trick that reappears in Count Occurrences and First and Last Position problems.
  • This function is so fundamental that standard libraries ship it verbatim: C++ has std::upper_bound, Python has bisect.bisect_right, Go has sort.Search. Interviewers still expect you to hand-roll it — the off-by-one traps are the whole point.
  • The record-and-shrink pattern here is the seed of binary search on the answer, the technique behind harder problems like allocating book pages or shipping packages within D days.

Asked at

AmazonMicrosoftOracleAdobe
Frequently Sometimes Occasionally
Example 1
Input: arr = [2, 3, 7, 10, 11, 11, 25], target = 9
Output: 3
arr[3] = 10 is the first element strictly greater than 9 — indices 0…2 hold 2, 3, 7, all smaller.
Example 2
Input: arr = [2, 3, 7, 10, 11, 11, 25], target = 11
Output: 6
The two 11s are equal to the target, not greater — the bound skips past both to arr[6] = 25.
Example 3
Input: arr = [2, 3, 7, 10, 11, 11, 25], target = 100
Output: 7
No element is greater than 100, so the upper bound is the array length, 7.
Constraints

- 1 <= arr.size <= 10^6 - 1 <= arr[i] <= 10^6 - 1 <= target <= 10^6 - arr is sorted in non-decreasing order

Solve this problem →