You are given a sorted array arr and an integer x. Your task is to find the ceil of x — the smallest element in arr that is greater than or equal to x — and return its 0-based index.
If no element in arr is greater than or equal to x, return -1.
Note: if the ceil value appears multiple times, return the index of its first occurrence.
arr that is greater than or equal to x. If x itself is present, x is its own ceil. You return the index of that element, not the value.[1, 1, 2] with x = 0 — both 1s qualify). The problem pins down a unique answer by asking for the leftmost index, which the sorted order makes well-defined.x is strictly greater than the last (largest) element — then nothing in the array is >= x, so no ceil exists.arr sorted (inserting before duplicates). The only difference is the out-of-range case: insert position would be n, while this problem maps it to -1.arr[mid] <= x, record mid and search right (lo = mid + 1); otherwise search left. It is the same boundary hunt approached from the other side.v and first occurrence of v + 1 (or first index with element > v). The difference of the two indices is the count — two O(log n) searches.Input: arr = [1, 2, 8, 10, 11, 12, 19], x = 5 Output: 2 The smallest element >= 5 is 8, at index 2.
Input: arr = [1, 2, 8, 10, 11, 12, 19], x = 20 Output: -1 No element is >= 20, so there is no ceil.
Input: arr = [1, 1, 2, 8, 10, 11, 12, 19], x = 0 Output: 0 The smallest element >= 0 is 1, which appears at indices 0 and 1. The first occurrence is index 0.
- 1 <= arr.size <= 10^6 - 1 <= arr[i] <= 10^6 - 0 <= x <= 10^6 - arr is sorted in non-decreasing order
Ceil in a Sorted Array is the friendliest doorway into the single most reusable binary-search variant: lower bound — find the first element that satisfies a condition. Master the boundary-hunting idea here and dozens of harder problems collapse into the same six lines of code.
lo and hi pointers; here we adapt it to find a boundary instead of an exact match.In plain English: scan the sorted array and report where the first element >= x sits. Formally: return the smallest index i such that arr[i] >= x, or -1 if no such index exists. Because arr is sorted, the first element >= x is automatically the smallest element >= x — and automatically the first occurrence of that value.
Worked example — arr = [1, 2, 8, 10, 11, 12, 19], x = 5
index: 0 1 2 3 4 5 6
arr: [ 1, 2, 8, 10, 11, 12, 19 ]
<x <x ✓ first element >= 5
answer: index 2 (value 8)
Asking two or three sharp questions before coding shows an interviewer you think about contracts, not just code.
“Is the array guaranteed to be sorted in non-decreasing order?”
Yes — and this guarantee is the entire reason binary search applies. If it could be unsorted, only a linear scan would be correct.
“Can the array contain duplicate values?”
Yes. That is why the statement pins down the tie-break: return the index of the first occurrence of the ceil value.
“What if x is larger than every element?”
There is no ceil — return -1. This is the only failure case.
“What if x is smaller than or equal to every element?”
The answer is index 0 — the very first element is already >= x.
“What about a single-element array?”
Return 0 if that element is >= x, otherwise -1. A great sanity test for the loop bounds.
“How large can the array be?”
Up to 10^6 elements. A linear scan still passes, but binary search in O(log n) is what the sorted input is inviting you to do — about 20 steps instead of a million.
Before I code, let me confirm a few things.
The array is sorted non-decreasing and may contain duplicates — so for ties I return the first occurrence, correct?
If x exceeds every element I return -1, and since it is sorted and can be up to a million elements, I will binary search for the boundary rather than scan linearly.
Every element is either < x or >= x, and because the array is sorted, all the < x elements sit on the left and all the >= x elements sit on the right — two contiguous zones with one boundary between them. The answer is simply the index where the second zone begins.
arr = [ 1 2 | 8 10 11 12 19 ] x = 5
< x | >= x
^ the boundary — index 2 is the answerProbe the middle element. If arr[mid] >= x, then mid is a candidate answer — but a better (smaller) index might exist to its left, so record it and search left. If arr[mid] < x, then mid and everything left of it are in the wrong zone — search right. Either way, half the array vanishes per step.
Because a match makes us keep looking left, the search never settles for a later duplicate. When the loop ends, the recorded candidate is the leftmost index with arr[i] >= x — exactly the first-occurrence rule the problem demands. No post-processing needed.
| Linear scan | Binary search | |
|---|---|---|
| Time | O(n) | O(log n) |
| Space | O(1) | O(1) |
| Steps at n = 10^6 | ~1,000,000 | ~20 |
Both full implementations, with traces and pitfalls, are in the Approaches selector below.
Key takeaway
This is the lower bound pattern: binary search for the first index whose element satisfies a condition (arr[i] >= x) by recording every match and continuing left. Any problem phrased as find the first / smallest element that… over sorted data is this exact loop with a different condition.
lo = 0, hi = n - 1, ans = -1
while lo <= hi:
mid = lo + (hi - lo) / 2
if arr[mid] >= x: ans = mid; hi = mid - 1 # candidate — look left
else: lo = mid + 1 # too small — look right
return ans