Absent Without Leave
A medium Python interview practice problem on DataDriven. Write the Python and run it against test cases, with instant feedback.
- Domain
- Python
- Difficulty
- medium
- Seniority
- L4
Problem
A monitoring export hands you the sorted, distinct record IDs that actually landed in a log, plus the inclusive lower and upper bounds of the ID range that should have been there. Return the [start, end] ranges covering every ID in [lower, upper] that is absent from nums, each range stretched as wide as it can go and a lone missing ID written as [x, x].
Between the first name and the last, the ones who never showed. Account for them.
Example 1
Input:
nums = [0,1,3,50,75], lower = 0, upper = 99
Output:
[[2,2],[4,49],[51,74],[76,99]]
Example 2
Input:
nums = [], lower = 1, upper = 5
Output:
[[1,5]]
Worked solution and explanation
What this really is
Strip the costume and this is contiguous-gap detection over a sorted sequence: you are reconstructing the holes between the values that are present. Anyone can see that 2 is missing from [0, 1, 3]. What separates candidates is the bookkeeping at the two ends (the gap before the first element and the trailing gap after the last) plus the off-by-one: a gap ends at num minus 1, not num, because num itself is present. Miss the trailing check and every range that runs to upper silently disappears.
How to get there
Step 1: Track the next expected ID
Hold a single cursor, expected, for the next ID you would hope to see. It starts at lower, not at the first element, so a gap that opens before nums[0] gets caught.
Step 2: Emit a gap whenever the cursor falls behind
When the current number jumps past expected, the stretch [expected, num - 1] is the gap. Then advance expected to num + 1, since num is now accounted for. A gap of width one falls out naturally as [x, x].
Step 3: Close out the tail
After the loop, expected may still sit at or below upper. That leftover is the trailing gap [expected, upper]. This is the line candidates forget, and it is the one the empty-list case depends on.
The solution
def find_missing_ranges(nums: list, lower: int, upper: int) -> list:
gaps = []
expected = lower
for num in nums:
if num > expected:
gaps.append([expected, num - 1])
expected = num + 1
if expected <= upper:
gaps.append([expected, upper])
return gapsCommon follow-up questions
- What if a single missing value should be reported as just x instead of [x, x]? (Tests collapsing [x, x] into a scalar at output time.)
- What changes if the input is no longer guaranteed sorted? (Tests sorting first, which adds an O(n log n) prepass.)
- How would you produce the same gap report directly in SQL? (Tests comparing each row against the previous one to find breaks in a sequence.)