228. Summary Ranges
Problem Description
You are given a sorted array of unique integers nums
. Your task is to find the smallest list of ranges that covers all numbers in the array exactly.
A range [a,b]
represents all integers from a
to b
inclusive. For example, the range [1,3]
includes the numbers 1, 2, and 3.
The goal is to group consecutive numbers in the array into ranges. Each number in nums
must belong to exactly one range, and the ranges should cover only the numbers that exist in nums
(no extra numbers).
The output format for each range depends on whether it contains a single number or multiple numbers:
- If a range contains only one number (like
[5,5]
), output it as"5"
- If a range contains multiple numbers (like
[1,3]
), output it as"1->3"
For example:
- If
nums = [0,1,2,4,5,7]
, the consecutive groups are[0,1,2]
,[4,5]
, and[7]
- The output would be
["0->2", "4->5", "7"]
The ranges must be returned in sorted order (which naturally happens when processing the sorted input array from left to right).
Intuition
Since the array is already sorted, consecutive numbers that form a range will appear next to each other. This makes the problem straightforward - we just need to identify where consecutive sequences start and end.
Think of walking through the sorted array and grouping numbers that are exactly 1 apart. When we encounter a number that isn't exactly 1 more than the previous number, we know we've found a break point between ranges.
For example, in [0,1,2,4,5,7]
:
- Starting at 0: we see 1 (which is 0+1), then 2 (which is 1+1) - these are consecutive
- At 4: this is not 2+1, so we've found a break. The range
[0,2]
ends here - Starting at 4: we see 5 (which is 4+1) - these are consecutive
- At 7: this is not 5+1, so we've found another break. The range
[4,5]
ends here - 7 stands alone as a single-element range
The key insight is using two pointers: one (i
) marks the start of a potential range, and another (j
) extends as far as possible while numbers remain consecutive. When we can't extend j
anymore (because nums[j+1] ≠ nums[j]+1
), we've found a complete range from i
to j
.
After recording this range, we move i
to where j
left off plus one position, and repeat the process. This ensures we examine each element exactly once while building our ranges efficiently.
Solution Approach
The solution uses a two-pointer technique to efficiently identify consecutive ranges in the sorted array.
Algorithm Steps:
-
Initialize pointers and result list: Start with pointer
i
at index 0 and create an empty listans
to store the range strings. -
Main loop: While
i
is within the array bounds:- Set
j = i
to mark the potential end of the current range - Extend the range: Keep moving
j
to the right while:j + 1 < n
(not at the end of array)nums[j + 1] == nums[j] + 1
(next number is consecutive)
- Format the range: Once we can't extend further, we have found a complete range from index
i
toj
:- If
i == j
: single element range, addstr(nums[i])
to result - If
i != j
: multi-element range, addf'{nums[i]}->{nums[j]}'
to result
- If
- Move to next range: Set
i = j + 1
to start searching for the next range
- Set
-
Return the result: The
ans
list contains all ranges in order.
Helper Function: The code uses a helper function f(i, j)
to format the range string:
def f(i: int, j: int) -> str:
return str(nums[i]) if i == j else f'{nums[i]}->{nums[j]}'
Example Walkthrough with nums = [0,1,2,4,5,7]
:
- Round 1:
i=0
, extendj
from 0→1→2 (stops at 2 because 4 ≠ 3), add"0->2"
- Round 2:
i=3
, extendj
from 3→4 (stops at 4 because 7 ≠ 6), add"4->5"
- Round 3:
i=5
,j
stays at 5 (can't extend), add"7"
- Result:
["0->2", "4->5", "7"]
Time Complexity: O(n)
where n
is the length of the array. Each element is visited exactly once.
Space Complexity: O(1)
excluding the output array, as we only use a constant amount of extra space for pointers.
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with nums = [0,2,3,4,6,8,9]
:
Initial State:
- Array:
[0,2,3,4,6,8,9]
i = 0
,ans = []
Round 1: Start at index i = 0
(value = 0)
- Set
j = 0
- Check if we can extend:
nums[1] = 2
, which is not0 + 1
- Can't extend, so range is just
[0]
- Since
i == j
, format as"0"
- Add
"0"
to result - Move
i = j + 1 = 1
Round 2: Start at index i = 1
(value = 2)
- Set
j = 1
- Check if we can extend:
nums[2] = 3
, which equals2 + 1
✓ - Extend
j = 2
- Check if we can extend:
nums[3] = 4
, which equals3 + 1
✓ - Extend
j = 3
- Check if we can extend:
nums[4] = 6
, which is not4 + 1
- Can't extend further, so range is
[2,3,4]
- Since
i ≠ j
(1 ≠ 3), format as"2->4"
- Add
"2->4"
to result - Move
i = j + 1 = 4
Round 3: Start at index i = 4
(value = 6)
- Set
j = 4
- Check if we can extend:
nums[5] = 8
, which is not6 + 1
- Can't extend, so range is just
[6]
- Since
i == j
, format as"6"
- Add
"6"
to result - Move
i = j + 1 = 5
Round 4: Start at index i = 5
(value = 8)
- Set
j = 5
- Check if we can extend:
nums[6] = 9
, which equals8 + 1
✓ - Extend
j = 6
- Check if we can extend:
j + 1 = 7
is out of bounds - Can't extend further, so range is
[8,9]
- Since
i ≠ j
(5 ≠ 6), format as"8->9"
- Add
"8->9"
to result - Move
i = j + 1 = 7
Termination: i = 7
is out of bounds, exit loop
Final Result: ["0", "2->4", "6", "8->9"]
Solution Implementation
1class Solution:
2 def summaryRanges(self, nums: List[int]) -> List[str]:
3 """
4 Given a sorted unique integer array, return the smallest sorted list of ranges
5 that cover all numbers in the array.
6
7 Args:
8 nums: A sorted array of unique integers
9
10 Returns:
11 A list of string ranges in format "a->b" or "a" for single elements
12 """
13
14 def format_range(start_idx: int, end_idx: int) -> str:
15 """
16 Format a range based on start and end indices.
17
18 Args:
19 start_idx: Starting index of the range
20 end_idx: Ending index of the range
21
22 Returns:
23 String representation of the range
24 """
25 # If start and end are the same, return single number
26 if start_idx == end_idx:
27 return str(nums[start_idx])
28 # Otherwise, return range format "start->end"
29 return f'{nums[start_idx]}->{nums[end_idx]}'
30
31 # Initialize variables
32 current_idx = 0
33 array_length = len(nums)
34 result = []
35
36 # Process all elements in the array
37 while current_idx < array_length:
38 # Mark the start of current range
39 range_end_idx = current_idx
40
41 # Extend the range while consecutive numbers exist
42 while range_end_idx + 1 < array_length and nums[range_end_idx + 1] == nums[range_end_idx] + 1:
43 range_end_idx += 1
44
45 # Add the formatted range to result
46 result.append(format_range(current_idx, range_end_idx))
47
48 # Move to the next unprocessed element
49 current_idx = range_end_idx + 1
50
51 return result
52
1class Solution {
2 /**
3 * Given a sorted unique integer array, return the smallest sorted list of ranges
4 * that cover all the numbers in the array exactly.
5 *
6 * @param nums sorted unique integer array
7 * @return list of string ranges in format "a->b" or "a"
8 */
9 public List<String> summaryRanges(int[] nums) {
10 List<String> result = new ArrayList<>();
11
12 // Iterate through the array to find consecutive ranges
13 int arrayLength = nums.length;
14 for (int startIndex = 0; startIndex < arrayLength; ) {
15 // Initialize end index to current start position
16 int endIndex = startIndex;
17
18 // Extend the range while numbers are consecutive
19 while (endIndex + 1 < arrayLength && nums[endIndex + 1] == nums[endIndex] + 1) {
20 endIndex++;
21 }
22
23 // Format and add the range to result list
24 result.add(formatRange(nums, startIndex, endIndex));
25
26 // Move to the next unprocessed element
27 startIndex = endIndex + 1;
28 }
29
30 return result;
31 }
32
33 /**
34 * Formats a range into string representation.
35 * Single element: "a"
36 * Multiple elements: "a->b"
37 *
38 * @param nums the array containing the values
39 * @param startIndex starting index of the range
40 * @param endIndex ending index of the range
41 * @return formatted string representation of the range
42 */
43 private String formatRange(int[] nums, int startIndex, int endIndex) {
44 // Check if range contains only one element
45 if (startIndex == endIndex) {
46 return String.valueOf(nums[startIndex]);
47 }
48 // Range contains multiple consecutive elements
49 return String.format("%d->%d", nums[startIndex], nums[endIndex]);
50 }
51}
52
1class Solution {
2public:
3 vector<string> summaryRanges(vector<int>& nums) {
4 vector<string> result;
5
6 // Lambda function to format range string
7 // If start == end, return single number; otherwise return "start->end"
8 auto formatRange = [&](int startIdx, int endIdx) {
9 if (startIdx == endIdx) {
10 return to_string(nums[startIdx]);
11 }
12 return to_string(nums[startIdx]) + "->" + to_string(nums[endIdx]);
13 };
14
15 int n = nums.size();
16
17 // Iterate through the array to find consecutive ranges
18 for (int startIdx = 0; startIdx < n; ) {
19 int endIdx = startIdx;
20
21 // Extend the range while numbers are consecutive
22 while (endIdx + 1 < n && nums[endIdx + 1] == nums[endIdx] + 1) {
23 endIdx++;
24 }
25
26 // Add the formatted range to result
27 result.emplace_back(formatRange(startIdx, endIdx));
28
29 // Move to the next unprocessed element
30 startIdx = endIdx + 1;
31 }
32
33 return result;
34 }
35};
36
1/**
2 * Converts a sorted array of unique integers into a list of range strings.
3 * Each range covers consecutive numbers in the array.
4 * @param nums - A sorted array of unique integers
5 * @returns An array of range strings in the format "a->b" or "a" for single elements
6 */
7function summaryRanges(nums: number[]): string[] {
8 /**
9 * Formats a range into a string representation.
10 * @param startIndex - The starting index of the range
11 * @param endIndex - The ending index of the range
12 * @returns A formatted range string
13 */
14 const formatRange = (startIndex: number, endIndex: number): string => {
15 // If start and end are the same, return single number
16 // Otherwise, return range format "start->end"
17 return startIndex === endIndex
18 ? `${nums[startIndex]}`
19 : `${nums[startIndex]}->${nums[endIndex]}`;
20 };
21
22 const arrayLength: number = nums.length;
23 const result: string[] = [];
24
25 // Iterate through the array to find consecutive ranges
26 let currentIndex: number = 0;
27 while (currentIndex < arrayLength) {
28 // Mark the start of a new range
29 let rangeEndIndex: number = currentIndex;
30
31 // Extend the range while numbers are consecutive
32 while (rangeEndIndex + 1 < arrayLength &&
33 nums[rangeEndIndex + 1] === nums[rangeEndIndex] + 1) {
34 rangeEndIndex++;
35 }
36
37 // Add the formatted range to results
38 result.push(formatRange(currentIndex, rangeEndIndex));
39
40 // Move to the next unprocessed element
41 currentIndex = rangeEndIndex + 1;
42 }
43
44 return result;
45}
46
Time and Space Complexity
Time Complexity: O(n)
where n
is the length of the input array nums
.
- The outer
while
loop iterates through each element in the array exactly once. The variablei
starts at 0 and jumps toj + 1
after each iteration, wherej
marks the end of a consecutive range. - The inner
while
loop also visits each element at most once throughout the entire execution. Although it appears nested, each element is checked only once for consecutiveness with its next element. - The helper function
f(i, j)
runs inO(1)
time as it performs a simple string concatenation or returns a single string value. - Therefore, the total time complexity is
O(n)
.
Space Complexity: O(1)
auxiliary space (excluding the output).
- The algorithm uses a constant amount of extra space with variables
i
,j
, andn
. - The helper function
f
doesn't use any additional space beyond the string it creates for the output. - The space used by the output list
ans
isO(k)
wherek
is the number of ranges, but this is not counted as auxiliary space since it's required for the output. - In the worst case where no consecutive numbers exist,
k = n
, making the output spaceO(n)
. - Therefore, the auxiliary space complexity is
O(1)
.
Common Pitfalls
1. Forgetting to Handle Empty Array
One of the most common oversights is not checking if the input array is empty before processing.
Problem Code:
def summaryRanges(self, nums: List[int]) -> List[str]:
current_idx = 0
array_length = len(nums)
result = []
while current_idx < array_length: # This works but could be more explicit
# ... rest of code
Why it's a pitfall: While the above code technically handles empty arrays correctly (the while loop won't execute), it's not immediately obvious and could lead to confusion during code reviews or debugging.
Better Solution:
def summaryRanges(self, nums: List[int]) -> List[str]:
# Explicitly handle empty array
if not nums:
return []
current_idx = 0
array_length = len(nums)
result = []
# ... rest of code
2. Off-by-One Error in Range Extension
A critical mistake is incorrectly checking the consecutive condition, especially with the array bounds.
Problem Code:
# WRONG: Checking nums[range_end_idx] instead of nums[range_end_idx + 1] while range_end_idx < array_length and nums[range_end_idx] == nums[range_end_idx - 1] + 1: range_end_idx += 1
Why it's a pitfall: This compares the current element with the previous one incorrectly and can cause index out of bounds errors or incorrect range detection.
Correct Solution:
# Check if the NEXT element is consecutive to current while range_end_idx + 1 < array_length and nums[range_end_idx + 1] == nums[range_end_idx] + 1: range_end_idx += 1
3. Integer Overflow with Large Numbers
When dealing with very large integers near the maximum integer value, adding 1 could theoretically cause overflow in some languages.
Problem Code:
# In languages with fixed integer sizes, this could overflow if nums[j + 1] == nums[j] + 1:
Why it's a pitfall: In Python, this isn't actually an issue due to arbitrary precision integers, but in languages like Java or C++, adding 1 to Integer.MAX_VALUE causes overflow.
Defensive Solution:
# More defensive approach using subtraction instead of addition while range_end_idx + 1 < array_length and nums[range_end_idx + 1] - nums[range_end_idx] == 1: range_end_idx += 1
4. Incorrect String Formatting
Using the wrong string formatting can lead to incorrect output format.
Problem Code:
# WRONG: Using comma or space instead of arrow
return f'{nums[start_idx]},{nums[end_idx]}' # Wrong: "0,2"
return f'{nums[start_idx]} {nums[end_idx]}' # Wrong: "0 2"
return f'{nums[start_idx]}-{nums[end_idx]}' # Wrong: "0-2" (single dash)
Correct Solution:
# Must use arrow notation with two characters "->"
return f'{nums[start_idx]}->{nums[end_idx]}' # Correct: "0->2"
5. Not Preserving Original Array Order
Some might be tempted to use a different approach that doesn't maintain the sorted order.
Problem Code:
# WRONG: Processing ranges in reverse or random order
result = []
# ... some logic that adds ranges out of order
return sorted(result) # Trying to fix order afterwards
Why it's a pitfall: The problem requires ranges to be in sorted order. Processing the sorted input array from left to right naturally maintains this order without additional sorting.
Correct Approach: Always process the array from left to right (index 0 to n-1) to maintain the natural sorted order of ranges.
What data structure does Breadth-first search typically uses to store intermediate states?
Recommended Readings
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!