Understand
30-second explanation
Build the interview-ready mental model before comparing implementations.
The array is sorted and has no duplicates, so consecutive runs of integers form the ranges. Walk once: remember where the current run started, and whenever the next number is not exactly one more than the current (or you hit the end), close the run — emit `"a"` if it's a single number or `"a->b"` if it spans more than one. One linear pass, O(n) time, O(1) extra space beyond the output.
Interview contextWhat is testedWhere candidates slipHow to stand outExplore interview contextHide interview context
What's being tested
Whether you exploit the 'sorted, no duplicates' precondition to do one clean linear pass, and whether you correctly handle the single-element range formatting and the empty input.
Where candidates slip
Emitting `"5->5"` for a lone number instead of `"5"`, or building ranges with an off-by-one that drops the last run or double-counts boundaries.
How to stand out
State the precondition out loud ('sorted + distinct ⇒ consecutive integers form runs'), handle empty up front, and mention the sibling problem Missing Ranges to show you see the pattern family.
Choose
Compare the available approaches
Use constraints and trade-offs to select the route you can defend in an interview.
Interactive decision treeInteractiveChoose the right approachFirst decision previewStart run at nums[i]i+1 < n AND nums[i+1] == nums[i]+1?YesNoExplore the full treeCollapse the tree
How to read it:Scan left to right; a break (next != current + 1) closes the current range.
Learn & trace
Build each solution step by step
Move from the core idea to a visual trace, implementation, proof, and edge cases.
Approach 1 of 1 · Optimal
Single Pass — Track Run Start (Optimal)
1Hint 1Explore hintHide hint
The array is sorted with no duplicates. What does it mean, then, when nums[i+1] is exactly nums[i] + 1 versus when it jumps by more?
2Hint 2Explore hintHide hint
Remember where the current consecutive run started. Keep extending while the next element is one bigger; the moment it isn't, you've found the end of a range.
3Hint 3Explore hintHide hint
When you close a range, emit "start" if start equals end, otherwise "start->end". Then start a fresh run at the next element.
A · Core idea
Because the array is sorted and contains no duplicates, a maximal range is precisely a maximal run of consecutive integers — values where each is exactly one more than the one before. The algorithm is a single left-to-right scan that remembers where the current run began and detects the instant the run breaks.
The core observation. Sortedness alone isn't enough; the absence of duplicates is what makes nums[i+1] == nums[i] + 1 a clean test for 'still in the same range'. If duplicates were allowed, two equal values would have a difference of 0 and the test would mislead. With both guarantees, the only two transitions are: the sequence continues (+1) or it jumps (gap > 1), and a jump is exactly a range boundary.
How the scan works. We set start = nums[i] at the beginning of each run. Then we advance an inner pointer as long as the next element keeps the run consecutive. When that inner loop stops, nums[i] is the run's end. We emit the range — "start" when start == end (a lone number), otherwise "start->end" — then step past end to begin the next run. Repeating until the array is consumed produces every range in sorted order automatically, because the input was sorted to begin with.
Why the single-element check matters. The output spec is explicit: a lone number is "5", not "5->5". This is the single most common bug on this problem. Comparing start and end before formatting handles it cleanly. The other classic slip is an off-by-one — emitting per element instead of per run, or forgetting to emit the final run after the loop ends; structuring the loop as 'extend while consecutive, then emit once' avoids both.
Overflow caution at the extremes. Values can be INT_MAX. Writing the consecutiveness test as nums[i+1] == nums[i] + 1 is fine in Python (arbitrary precision) but in Java nums[i] + 1 could overflow if nums[i] were INT_MAX — though since the array is strictly increasing, a value equal to INT_MAX can only be the last element, so nums[i+1] wouldn't exist. Still, comparing as (long) nums[i] + 1 or checking nums[i+1] - nums[i] != 1 with care is the defensive habit worth voicing.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
nums = [0,1,2,4,5,7]How to read it:Vertical bars mark where a run ends because the next value isn't consecutive.
["0->2","4->5","7"]C · Code with teaching comments
D · Why it works and complexityO(n) timeO(1) spaceOpen the invariant and proofExplore the proofHide the proof
Pre-sorted input is a gift: it converts 'group consecutive elements' into a single forward scan that detects breaks. The same skeleton — remember the start, extend while a predicate holds, emit on break — generalizes to run-length encoding, Missing Ranges (emit the gaps instead of the runs), and counting contiguous segments.
ComplexityO(n) time, O(1) space — Each element is visited exactly once by the combined outer/inner pointer advancement → O(n) time. Only a few scalar variables are used; the output list isn't counted as extra working space → O(1) auxiliary space.
E · Edge cases and pitfalls8nums = [] — Outer while never runs; returns [].Explore edge casesHide edge cases
Edge cases handled
nums = []Outer while never runs; returns [].nums = [5]start=end=5 → "5" (single-element formatting).nums = [-3,-2,-1,0]Negatives are consecutive too → "-3->0".nums = [1,3,5,7]No consecutive pairs → ["1","3","5","7"], every run length 1.
Pitfalls
- Formatting a single number as "a->a" instead of "a".
- Off-by-one that drops the final run — make sure the emit happens after the inner loop, every iteration.
- Testing nums[i+1] - nums[i] == 1 in Java where the subtraction could overflow at extremes — prefer nums[i+1] == nums[i] + 1 or use long.
- Forgetting the empty-array guard.
Practice
Try the solution yourself
Edit the optimal implementation, test another input, and observe the result.
Editable code previewpublic List<String> summaryRanges(int[] nums) { List<String> out = new ArrayList<>(); int n = nums.length; int i = 0; while (i < n) {Explore the playgroundClose the playground
Avoid mistakes
Recognize the interview traps
Understand why common attempts fail before reviewing the corrected implementation.
1Formatting a lone number as "a->a"
The spec says a single number must be "a", not "a->a". Always compare start and end before formatting.
Explore the code comparisonHide the code comparison
Formatting a lone number as "a->a"
The spec says a single number must be "a", not "a->a". Always compare start and end before formatting.
Don't write this
out.append(f"{start}->{end}") # produces "5->5" for a single valueWrite this instead
out.append(str(start) if start == end else f"{start}->{end}")2Off-by-one that drops the last run
If you only emit when you *see* a break, the final run (which ends at the array boundary, not a break) never gets emitted. Structure the loop to emit after each inner-extend completes.
Explore the code comparisonHide the code comparison
Off-by-one that drops the last run
If you only emit when you *see* a break, the final run (which ends at the array boundary, not a break) never gets emitted. Structure the loop to emit after each inner-extend completes.
Don't write this
for (int i = 0; i < n; i++) {
if (i + 1 < n && nums[i+1] == nums[i] + 1) continue;
// emits only at breaks — but also forgets where start was
}Write this instead
int i = 0;
while (i < n) {
int start = nums[i];
while (i + 1 < n && nums[i + 1] == nums[i] + 1) i++;
int end = nums[i];
out.add(start == end ? Integer.toString(start) : start + "->" + end);
i++;
}3Overflow in the consecutiveness test
In Java, nums[i] + 1 overflows if nums[i] == INT_MAX. Although a strictly increasing array can only hold INT_MAX as its last element (so the +1 is never reached), defensive code uses long or compares as nums[i+1] == nums[i] + 1 only when i+1 exists.
Explore the code comparisonHide the code comparison
Overflow in the consecutiveness test
In Java, nums[i] + 1 overflows if nums[i] == INT_MAX. Although a strictly increasing array can only hold INT_MAX as its last element (so the +1 is never reached), defensive code uses long or compares as nums[i+1] == nums[i] + 1 only when i+1 exists.
Don't write this
while (i + 1 < n && nums[i + 1] - nums[i] == 1 && nums[i] == Integer.MAX_VALUE) { /* fragile */ }Write this instead
while (i + 1 < n && (long) nums[i + 1] == (long) nums[i] + 1) { i++; }Revise
Carry the pattern into the interview
Pattern to remember
Single pass, track run start, close on a break in consecutiveness
Code pattern to memorize
i = 0
while i < n:
start = nums[i]
while i + 1 < n and nums[i+1] == nums[i] + 1: i += 1
end = nums[i]
out.append(str(start) if start == end else f"{start}->{end}")
i += 1Rules to remember
- 1The input is sorted and distinct — that's the whole reason consecutive integers (
nums[i+1] == nums[i] + 1) define a range. - 2Compare with
nums[i] + 1, notnums[i+1] - nums[i] == 1blindly across signed overflow — values fit in 32-bit but along/careful compare avoids edge surprises at INT_MAX. - 3Emit
"a"whenstart == end, else"a->b"— forgetting the single-element case produces"5->5". - 4Advance the inner pointer while the run continues, then emit once — don't emit per element.
- 5Handle the empty array up front: return an empty list, no ranges.
Use this pattern when
- Compress a sorted, distinct integer array into consecutive ranges
- 'Group adjacent / consecutive runs' over already-ordered data
- Summarize gaps in a sequence (the complement is Missing Ranges)
- Any single-pass run-length style scan over sorted input
Choose another pattern when
- Array is unsorted → sort first, or this consecutiveness test is meaningless
- Duplicates allowed → the `+1` test breaks; you'd need run-length on equal values instead
- You need to MERGE overlapping [start,end] intervals → that's Merge Intervals, sort by start and sweep
- You must find which numbers are missing → Missing Ranges, scan the gaps not the runs
Interview takeaway
Summary Ranges is the gentlest 'scan a sorted array and group consecutive elements' problem. The reusable idea: when input is pre-sorted, a single pass that detects 'breaks' (where the next element stops being consecutive) turns into ranges, run-lengths, or gap reports — the same skeleton powers Missing Ranges and run-length encoding.
Continue
Transfer the pattern to another problem
Use a direct variation or pattern sibling to prove the idea is reusable.
Transferable patternSingle-pass run detection over a sorted, distinct array. Recognize it when pre-sorted input lets you group consecutive elements by detecting 'breaks' where the next element stops being one greater. The same scan, with the emit logic flipped to the gaps, solves Missing Ranges; generalized to [start,end] pairs it becomes the Merge Intervals family.
Practice queueDirect variations and pattern siblings
Direct follow-ups
- Missing RangesComing soonThe complement — emit the GAPS between consecutive numbers instead of the runs.
- Merge IntervalsGiven [start,end] pairs (possibly overlapping), sort by start and merge — the interval cousin.
- Insert IntervalInsert one interval into a sorted disjoint list and merge overlaps in a three-phase sweep.
- Teemo AttackingComing soonAnother sorted-time scan; sum durations, capping overlaps — same single-pass shape.