面试经典150题[048]:汇总区间(LeetCode 228)
汇总区间(LeetCode 228)
题目链接:汇总区间(LeetCode 228)
难度:简单
1. 题目描述
给定一个 无重复元素 的 有序 整数数组 nums 。
区间 [a,b] 是从 a 到 b(包含)的所有整数的集合。
返回 恰好覆盖数组中所有数字 的 最小有序 区间范围列表 。也就是说,nums 的每个元素都恰好被某个区间范围所覆盖,并且不存在属于某个区间但不属于 nums 的数字 x 。
列表中的每个区间范围 [a,b] 应该按如下格式输出:
“a->b” ,如果 a != b
“a” ,如果 a == b
示例 1:
输入:nums = [0,1,2,4,5,7]
输出:[“0->2”,“4->5”,“7”]
解释:区间范围是:
[0,2] --> “0->2”
[4,5] --> “4->5”
[7,7] --> “7”
示例 2:
输入:nums = [0,2,3,4,6,8,9]
输出:[“0”,“2->4”,“6”,“8->9”]
解释:区间范围是:
[0,0] --> “0”
[2,4] --> “2->4”
[6,6] --> “6”
[8,9] --> “8->9”
提示:
0 <= nums.length <= 20
-231 <= nums[i] <= 231 - 1
nums 中的所有值都 互不相同
nums 按升序排列
2. 问题分析
2.1 规律
- 数组有序且无重复,连续数字可以合并成区间,非连续则需拆分。
- 核心问题:如何高效识别连续序列并格式化输出?
- 由于数组小(n<=20),简单遍历即可,但算法通用性强,可扩展到更大规模。
2.2 贪心思路
我们使用线性遍历(类似贪心,每次尽可能延长当前区间):
- 如果数组为空,返回空列表。
- 初始化结果列表,设置当前区间起始
start = nums[0]
。 - 遍历数组从索引1开始:
- 如果当前元素
nums[i]
不等于前一个nums[i-1] + 1
,说明断开:- 添加区间:如果
start == nums[i-1]
,添加单点字符串;否则添加 “start->end”。 - 更新
start = nums[i]
为新区间起始。
- 添加区间:如果
- 如果当前元素
- 遍历结束后,添加最后一个区间(同上逻辑)。
- 该方法确保每个连续段被精确捕获,无多余计算。
3. 代码实现
Python
from typing import Listclass Solution:def summaryRanges(self, nums: List[int]) -> List[str]:if not nums:return []res = []start = nums[0]for i in range(1, len(nums)):if nums[i] != nums[i-1] + 1:if start == nums[i-1]:res.append(str(start))else:res.append(f"{start}->{nums[i-1]}")start = nums[i]# 添加最后一个区间if start == nums[-1]:res.append(str(start))else:res.append(f"{start}->{nums[-1]}")return res
C++
#include <vector>
#include <string>class Solution {
public:std::vector<std::string> summaryRanges(std::vector<int>& nums) {if (nums.empty()) return {};std::vector<std::string> res;int start = nums[0];for (size_t i = 1; i < nums.size(); ++i) {if (nums[i] != nums[i-1] + 1) {if (start == nums[i-1]) {res.push_back(std::to_string(start));} else {res.push_back(std::to_string(start) + "->" + std::to_string(nums[i-1]));}start = nums[i];}}// 添加最后一个区间if (start == nums.back()) {res.push_back(std::to_string(start));} else {res.push_back(std::to_string(start) + "->" + std::to_string(nums.back()));}return res;}
};
4. 复杂度分析
- 时间复杂度:O(n),只遍历一次数组,每个元素最多被访问一次
- 空间复杂度:O(1),除了输出列表外,只使用常数额外空间
5. 总结
- 有序数组合并区间 → 线性遍历是首选
- 核心维护区间起始点,很通用
- 类似滑动窗口或双指针,但更简单
- 可扩展到允许重复或无序的变体
复习
面试经典150题[018]:整数转罗马数字(LeetCode 12)
面试经典150题[033]:最小覆盖子串(LeetCode 76)