Skip to content
← All posts

Summary Ranges: Grouping Consecutive Numbers

4 min read
leetcodeproblemeasyarrays

Summary Ranges is LeetCode 228, rated Easy. You are given a sorted array of unique integers and need to return the smallest sorted list of ranges that cover every number in the array. If a range contains more than one element, format it as "a->b". If it contains just a single element, return "a" by itself.

For example, [0, 1, 2, 4, 5, 7] becomes ["0->2", "4->5", "7"]. The numbers 0, 1, and 2 are consecutive, so they collapse into one range. Same for 4 and 5. The 7 stands alone.

012345012457"0->2""4->5""7"
[0,1,2,4,5,7] splits into three consecutive groups: 0-2, 4-5, and the singleton 7.

The approach: scan and track range boundaries

The array is already sorted and contains no duplicates, which makes this problem clean. You walk through the array from left to right, keeping track of where the current range started. At each index, you check whether the current element is consecutive to the previous one (that is, whether nums[i] == nums[i - 1] + 1).

If it is consecutive, you do nothing and keep extending the range. If it is not consecutive, you have found a gap. That means the previous range just ended, so you close it and record the result. Then you start a fresh range at the current element.

After the loop finishes, you still have one open range that has not been closed yet. You close it and add it to the result. The entire algorithm is a single pass through the array with no extra data structures beyond the output list.

The solution

def summaryRanges(nums):
    if not nums:
        return []

    ranges = []
    start = 0

    for i in range(1, len(nums)):
        if nums[i] != nums[i - 1] + 1:
            if start == i - 1:
                ranges.append(str(nums[start]))
            else:
                ranges.append(f"{nums[start]}->{nums[i - 1]}")
            start = i

    if start == len(nums) - 1:
        ranges.append(str(nums[start]))
    else:
        ranges.append(f"{nums[start]}->{nums[-1]}")

    return ranges
  1. Empty check. If the array is empty, return an empty list immediately. This avoids index errors.
  2. The start pointer. This tracks the beginning index of the current range. It resets every time you detect a gap.
  3. Gap detection. When nums[i] is not equal to nums[i - 1] + 1, the consecutive streak is broken. You close the range from nums[start] to nums[i - 1].
  4. Singleton vs. multi-element range. If start == i - 1 (or start == len(nums) - 1 for the final range), the range has only one element, so you output just that number. Otherwise, you format it as "a->b".
  5. Closing the last range. After the loop, the final range is still open. The code after the loop handles it with the same singleton-or-range logic.
  6. String formatting. Python f-strings make it easy to build the "a->b" format. The arrow -> is just a literal string, not a special operator.

Step-by-step walkthrough

Step 1: Start at index 0, value 0. Begin a new range.

001122435475i=0result: []

Range start = 0. No previous element to compare against.

Step 2: Index 1, value 1. Consecutive (1 = 0 + 1), extend range.

001122435475i=1result: []

1 follows 0 consecutively. The current range is still growing: [0..1].

Step 3: Index 2, value 2. Consecutive (2 = 1 + 1), extend range.

001122435475i=2result: []

2 follows 1 consecutively. The current range extends to [0..2].

Step 4: Index 3, value 4. Gap found (4 != 2 + 1). Close range, start new one.

001122435475i=3result: ["0->2"]

4 is not consecutive to 2. Close the range as "0->2" and begin a new range at 4.

Step 5: Index 4, value 5. Consecutive (5 = 4 + 1), extend range.

001122435475i=4result: ["0->2"]

5 follows 4 consecutively. The current range grows to [4..5].

Step 6: Index 5, value 7. Gap found (7 != 5 + 1). Close range, start new one.

001122435475i=5result: ["0->2", "4->5"]

7 is not consecutive to 5. Close the range as "4->5" and begin a new range at 7.

Step 7: End of array. Close the final range.

001122435475result: ["0->2", "4->5", "7"]

No more elements. Close the last range as "7". Result: ["0->2", "4->5", "7"].

Complexity analysis

MetricValueWhy
TimeO(n)Single pass through the array, constant work per element
SpaceO(1)Only a few variables beyond the output list (excluding the output itself)

Building blocks

This problem teaches three reusable techniques that appear across many array problems.

1. Consecutive element detection

Checking whether adjacent sorted elements differ by exactly 1 is the core pattern here. You will see the same idea in problems that ask you to find the longest consecutive sequence, count groups, or identify missing numbers.

2. Tracking range boundaries with a start pointer

Instead of storing entire subarrays, you keep a single start index and compute the range when you need it. This "lazy range" approach saves space and simplifies the logic. The same idea powers sliding window problems where you track a window with two pointers.

3. Post-loop cleanup

Many scanning algorithms have leftover state after the loop ends. Here, the last range is still open. Remembering to handle this final piece is a common source of bugs, and practicing it here builds the habit for harder problems.

Edge cases

  • Empty array. Return []. No elements means no ranges.
  • Single element. [5] returns ["5"]. The loop body never executes, and the post-loop code handles the one element.
  • All consecutive. [1, 2, 3, 4, 5] returns ["1->5"]. The entire array is one range.
  • No consecutive pairs. [1, 3, 5, 7] returns ["1", "3", "5", "7"]. Every element is its own range.
  • Negative numbers. [-3, -2, -1, 1] returns ["-3->-1", "1"]. The algorithm works the same way with negatives since it only checks differences.
  • Two elements, consecutive. [0, 1] returns ["0->1"]. The simplest multi-element range.

A common mistake is forgetting to close the last range after the loop ends. Every time you write a scan-and-accumulate loop, ask yourself: "Is there leftover state that still needs to be flushed?" For Summary Ranges, the answer is always yes.

From understanding to recall

Summary Ranges is a short problem, but the pattern it uses (scanning for groups in a sorted array and tracking boundaries) is surprisingly common. Merge Intervals, Missing Ranges, and Remove Duplicates from Sorted Array all rely on the same idea of walking through sorted data and reacting to transitions.

Reading through this solution once is not enough to make the pattern stick. Spaced repetition helps you internalize the scan-and-track approach so that the next time you see a problem about grouping sorted elements, you reach for the right building blocks automatically. CodeBricks breaks this problem into its core pieces and drills them at increasing intervals until they become second nature.

Related problems

  • Merge Intervals uses the same idea of processing sorted ranges and deciding when to extend or close them
  • Remove Duplicates from Sorted Array is another single-pass scan over a sorted array, detecting transitions between distinct values
  • Contains Duplicate teaches the "have I seen this before?" pattern, which complements the consecutive-check approach used here