🧠
Optimal Approach (Using Binary Search to Find Missing Ranges)
💡 This approach uses binary search to quickly find the position of boundaries and missing ranges, useful if nums is very large and range is huge.
Intuition
Use binary search to find the next number after a missing range start, then jump to that position to find the next gap, skipping unnecessary checks.
Algorithm
- Initialize a pointer at lower.
- While pointer ≤ upper, use binary search to find the smallest number in nums ≥ pointer.
- If pointer < found number, record missing range from pointer to found number - 1.
- Update pointer to found number + 1 and repeat.
- If no number found, record missing range from pointer to upper and stop.
💡 Binary search lets us skip large chunks of the range by jumping to known numbers in nums.
import bisect
def find_missing_ranges(nums, lower, upper):
missing = []
pointer = lower
while pointer <= upper:
idx = bisect.bisect_left(nums, pointer)
if idx == len(nums):
# No more numbers in nums >= pointer
if pointer <= upper:
if pointer == upper:
missing.append(str(pointer))
else:
missing.append(f"{pointer}->{upper}")
break
curr = nums[idx]
if pointer < curr:
end = curr - 1
if pointer == end:
missing.append(str(pointer))
else:
missing.append(f"{pointer}->{end}")
pointer = curr + 1
return missing
# Example usage
if __name__ == "__main__":
nums = [0, 1, 3, 50, 75]
lower = 0
upper = 99
print(find_missing_ranges(nums, lower, upper))
Line Notes
import bisectUse built-in binary search module for efficient searching
pointer = lowerStart scanning from lower boundary
idx = bisect.bisect_left(nums, pointer)Find index of smallest number >= pointer
if idx == len(nums):No more numbers in nums beyond pointer
if pointer == upper:Single number missing range at end
missing.append(f"{pointer}->{upper}")Add missing range to end
pointer = curr + 1Jump pointer past current number to find next gap
import java.util.*;
public class MissingRanges {
public static List<String> findMissingRanges(int[] nums, int lower, int upper) {
List<String> missing = new ArrayList<>();
int pointer = lower;
while (pointer <= upper) {
int idx = Arrays.binarySearch(nums, pointer);
if (idx < 0) idx = -idx - 1;
if (idx == nums.length) {
if (pointer <= upper) {
if (pointer == upper) missing.add(String.valueOf(pointer));
else missing.add(pointer + "->" + upper);
}
break;
}
int curr = nums[idx];
if (pointer < curr) {
int end = curr - 1;
if (pointer == end) missing.add(String.valueOf(pointer));
else missing.add(pointer + "->" + end);
}
pointer = curr + 1;
}
return missing;
}
public static void main(String[] args) {
int[] nums = {0, 1, 3, 50, 75};
int lower = 0, upper = 99;
System.out.println(findMissingRanges(nums, lower, upper));
}
}
Line Notes
int idx = Arrays.binarySearch(nums, pointer);Use binary search to find position of pointer in nums
if (idx < 0) idx = -idx - 1;Convert negative insertion point to index of next larger element
if (idx == nums.length) {No more numbers in nums beyond pointer
if (pointer == upper) missing.add(String.valueOf(pointer));Single number missing range at end
missing.add(pointer + "->" + upper);Add missing range to end
pointer = curr + 1;Jump pointer past current number to find next gap
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
vector<string> findMissingRanges(vector<int>& nums, int lower, int upper) {
vector<string> missing;
int pointer = lower;
while (pointer <= upper) {
auto it = lower_bound(nums.begin(), nums.end(), pointer);
if (it == nums.end()) {
if (pointer <= upper) {
if (pointer == upper) missing.push_back(to_string(pointer));
else missing.push_back(to_string(pointer) + "->" + to_string(upper));
}
break;
}
int curr = *it;
if (pointer < curr) {
int end = curr - 1;
if (pointer == end) missing.push_back(to_string(pointer));
else missing.push_back(to_string(pointer) + "->" + to_string(end));
}
pointer = curr + 1;
}
return missing;
}
int main() {
vector<int> nums = {0, 1, 3, 50, 75};
int lower = 0, upper = 99;
vector<string> result = findMissingRanges(nums, lower, upper);
for (auto& s : result) cout << s << " ";
cout << endl;
return 0;
}
Line Notes
auto it = lower_bound(nums.begin(), nums.end(), pointer);Binary search to find first number >= pointer
if (it == nums.end()) {No more numbers in nums beyond pointer
if (pointer == upper) missing.push_back(to_string(pointer));Single number missing range at end
missing.push_back(to_string(pointer) + "->" + to_string(upper));Add missing range to end
pointer = curr + 1;Jump pointer past current number to find next gap
int curr = *it;Dereference iterator to get current number
function findMissingRanges(nums, lower, upper) {
const missing = [];
let pointer = lower;
while (pointer <= upper) {
let left = 0, right = nums.length - 1;
let idx = nums.length;
while (left <= right) {
let mid = Math.floor((left + right) / 2);
if (nums[mid] >= pointer) {
idx = mid;
right = mid - 1;
} else {
left = mid + 1;
}
}
if (idx === nums.length) {
if (pointer <= upper) {
if (pointer === upper) missing.push(pointer.toString());
else missing.push(`${pointer}->${upper}`);
}
break;
}
let curr = nums[idx];
if (pointer < curr) {
let end = curr - 1;
if (pointer === end) missing.push(pointer.toString());
else missing.push(`${pointer}->${end}`);
}
pointer = curr + 1;
}
return missing;
}
// Example usage
console.log(findMissingRanges([0, 1, 3, 50, 75], 0, 99));
Line Notes
while (left <= right) {Perform binary search to find first number >= pointer
if (nums[mid] >= pointer) {Adjust right pointer to find leftmost suitable index
idx = mid;Update candidate index for binary search result
if (idx === nums.length) {No more numbers in nums beyond pointer
if (pointer === upper) missing.push(pointer.toString());Single number missing range at end
missing.push(`${pointer}->${upper}`);Add missing range to end
pointer = curr + 1;Jump pointer past current number to find next gap
TimeO(n log n) worst case
SpaceO(1) extra space besides output
Each iteration uses binary search O(log n) and pointer moves forward, total O(n log n) in worst case.
💡 This is efficient if range is huge but nums is small, as we skip large gaps quickly.
Interview Verdict: Accepted, useful for very large ranges
Binary search is a good optimization when the range is huge compared to nums size.