Last Updated: March 31, 2026
At first glance, this seems simple: just find the gaps between consecutive numbers in the array, relative to a given range. But there are a few subtleties that make it tricky. The range [lower, upper] extends beyond the array itself, so you need to account for gaps before the first element and after the last element.
The key observation is that the array is already sorted and contains unique values. So the "gaps" are just the spaces between consecutive elements (including the boundaries lower and upper). If you think of it as walking through a series of expected values and checking whether each one exists, the problem becomes a straightforward linear scan.
0 <= nums.length <= 100 → With n up to 100, even O(n^2) is trivially fast. The focus here is on correctness and clean logic, not performance optimization.-10^9 <= lower <= upper <= 10^9 → Values span a large integer range. Watch out for integer overflow if you try arithmetic like upper - lower + 1 in languages with fixed-width integers.nums is sorted and unique → No need to sort or deduplicate. We can rely on the ordering for a single linear pass.The most straightforward way to think about this: walk through the array and check three types of gaps separately. First, is there a gap between lower and the first element? Then, are there gaps between consecutive elements? Finally, is there a gap between the last element and upper?
This approach handles each case with its own block of code, which is easy to understand but a bit repetitive.
nums is empty: the entire range [lower, upper] is missing.lower and nums[0]. If lower < nums[0], add the range [lower, nums[0] - 1].nums[i] and nums[i+1], check if nums[i+1] - nums[i] > 1. If so, add the range [nums[i] + 1, nums[i+1] - 1].nums[n-1] and upper. If nums[n-1] < upper, add the range [nums[n-1] + 1, upper].This approach works correctly but handles three separate cases with nearly identical logic. What if we could unify all gap checks into a single loop using virtual boundary elements?
If we treat lower - 1 as a virtual element before the array and upper + 1 as a virtual element after the array, then every gap check follows the exact same pattern. We no longer need separate code for "before the first element," "between elements," and "after the last element." They all become gaps between consecutive entries in an extended sequence.
The trick is that lower - 1 and upper + 1 act as "virtual fence posts" around the array. Every pair of consecutive fence posts (whether real or virtual) is checked identically. If the gap between them is more than 1, there are missing numbers in between. The range [prev + 1, curr - 1] captures exactly those missing numbers.
This works for the empty array too. When nums is empty, the loop runs once with prev = lower - 1 and curr = upper + 1. If upper + 1 - (lower - 1) > 1 (which simplifies to upper >= lower, always true given the constraints), we add the range [lower, upper]. No special case needed.
prev = lower - 1. This represents the element "just before" the range starts.nums[i], check if nums[i] - prev > 1. If so, add the range [prev + 1, nums[i] - 1] to the result.prev = nums[i].upper + 1 - prev > 1 (equivalently, prev < upper), add the range [prev + 1, upper].