LeetCode 228: Summary Ranges (Single Pass Range Compression)
LeetCode 228ArrayTwo PointersToday we solve LeetCode 228 - Summary Ranges.
Source: https://leetcode.com/problems/summary-ranges/
English
Problem Summary
Given a sorted integer array with unique values, compress consecutive numbers into range strings. A single value is written as "x"; a run from a to b is written as "a->b".
Key Insight
The array is already sorted and unique, so each maximal consecutive run can be detected by advancing while nums[j + 1] == nums[j] + 1. Each run contributes exactly one output string.
Algorithm
1) Start pointer i at 0.
2) Set start = nums[i], and move i forward while values stay consecutive.
3) Let end = nums[i] after expansion.
4) Append start if start == end, otherwise append start->end.
5) Continue from next index until done.
Complexity
Time: O(n), each element is visited once.
Space: O(1) extra (excluding output list).
Reference Implementations (Java / Go / C++ / Python / JavaScript)
class Solution {
public List<String> summaryRanges(int[] nums) {
List<String> ans = new ArrayList<>();
int n = nums.length;
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];
if (start == end) {
ans.add(String.valueOf(start));
} else {
ans.add(start + "->" + end);
}
i++;
}
return ans;
}
}import "strconv"
func summaryRanges(nums []int) []string {
ans := make([]string, 0)
n := len(nums)
i := 0
for i < n {
start := nums[i]
for i+1 < n && nums[i+1] == nums[i]+1 {
i++
}
end := nums[i]
if start == end {
ans = append(ans, strconv.Itoa(start))
} else {
ans = append(ans, strconv.Itoa(start)+"->"+strconv.Itoa(end))
}
i++
}
return ans
}class Solution {
public:
vector<string> summaryRanges(vector<int>& nums) {
vector<string> ans;
int n = (int)nums.size();
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];
if (start == end) {
ans.push_back(to_string(start));
} else {
ans.push_back(to_string(start) + "->" + to_string(end));
}
i++;
}
return ans;
}
};class Solution:
def summaryRanges(self, nums: List[int]) -> List[str]:
ans = []
n = len(nums)
i = 0
while i < n:
start = nums[i]
while i + 1 < n and nums[i + 1] == nums[i] + 1:
i += 1
end = nums[i]
if start == end:
ans.append(str(start))
else:
ans.append(f"{start}->{end}")
i += 1
return ans/**
* @param {number[]} nums
* @return {string[]}
*/
var summaryRanges = function(nums) {
const ans = [];
let i = 0;
while (i < nums.length) {
const start = nums[i];
while (i + 1 < nums.length && nums[i + 1] === nums[i] + 1) {
i++;
}
const end = nums[i];
if (start === end) {
ans.push(String(start));
} else {
ans.push(`${start}->${end}`);
}
i++;
}
return ans;
};中文
题目概述
给定一个有序且无重复的整数数组,把连续数字压缩成区间字符串:单个数字输出 "x",连续区间 [a,b] 输出 "a->b"。
核心思路
因为数组有序且去重,连续段天然是“最大连续块”。我们只需要从每一段的起点出发,一路扩展到该段终点,再一次性产出一个字符串。
算法步骤
1)指针 i 指向当前段起点,记作 start。
2)当 nums[i+1] == nums[i] + 1 时持续右移。
3)停止后 nums[i] 即当前段终点 end。
4)若 start == end,加入单值字符串;否则加入区间字符串。
5)继续处理下一段。
复杂度分析
时间复杂度:O(n)。
空间复杂度:额外 O(1)(不计输出结果)。
多语言参考实现(Java / Go / C++ / Python / JavaScript)
class Solution {
public List<String> summaryRanges(int[] nums) {
List<String> ans = new ArrayList<>();
int n = nums.length;
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];
if (start == end) {
ans.add(String.valueOf(start));
} else {
ans.add(start + "->" + end);
}
i++;
}
return ans;
}
}import "strconv"
func summaryRanges(nums []int) []string {
ans := make([]string, 0)
n := len(nums)
i := 0
for i < n {
start := nums[i]
for i+1 < n && nums[i+1] == nums[i]+1 {
i++
}
end := nums[i]
if start == end {
ans = append(ans, strconv.Itoa(start))
} else {
ans = append(ans, strconv.Itoa(start)+"->"+strconv.Itoa(end))
}
i++
}
return ans
}class Solution {
public:
vector<string> summaryRanges(vector<int>& nums) {
vector<string> ans;
int n = (int)nums.size();
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];
if (start == end) {
ans.push_back(to_string(start));
} else {
ans.push_back(to_string(start) + "->" + to_string(end));
}
i++;
}
return ans;
}
};class Solution:
def summaryRanges(self, nums: List[int]) -> List[str]:
ans = []
n = len(nums)
i = 0
while i < n:
start = nums[i]
while i + 1 < n and nums[i + 1] == nums[i] + 1:
i += 1
end = nums[i]
if start == end:
ans.append(str(start))
else:
ans.append(f"{start}->{end}")
i += 1
return ans/**
* @param {number[]} nums
* @return {string[]}
*/
var summaryRanges = function(nums) {
const ans = [];
let i = 0;
while (i < nums.length) {
const start = nums[i];
while (i + 1 < nums.length && nums[i + 1] === nums[i] + 1) {
i++;
}
const end = nums[i];
if (start === end) {
ans.push(String(start));
} else {
ans.push(`${start}->${end}`);
}
i++;
}
return ans;
};
Comments