题目来源:LeetCode 352. 将数据流变为多个不相交区间
问题抽象: 设计一个 SummaryRanges 类,用于将数据流中的整数动态合并为 多个不相交区间,支持以下核心操作:
-
核心功能:
- 初始化:创建空区间集合(无任何区间);
- 添加整数:
addNum(int val)将新整数val插入数据流; - 获取区间:
getIntervals()返回当前所有不相交区间的有序列表(格式List<int[]>)。
-
区间合并规则:
- 新区间生成:若
val不与任何区间相邻,则生成新区间[val, val]; - 区间扩展:若
val与某区间端点相邻(如[1,3]插入4→ 扩展为[1,4]); - 区间合并:若
val连接两个区间(如[1,3]和[5,7]插入4→ 合并为[1,7])。
- 新区间生成:若
-
状态维护:
- 去重处理:重复添加的
val直接忽略(不改变区间结构); - 有序存储:区间按起始值升序排列(无重叠);
- 高效合并:避免每次遍历所有区间(利用有序性二分查找插入点)。
- 去重处理:重复添加的
-
边界处理:
- 空数据流:
getIntervals()返回空列表; - 孤立值:
addNum(5)后区间为[[5,5]]; - 连续扩展:
- 初始:
[[1,1]] addNum(2)→[[1,2]]addNum(4)→[[1,2],[4,4]]addNum(3)→[[1,4]](连接[1,2]和[4,4]);
- 初始:
- 大值域:
val范围为 32 位有符号整数。
- 空数据流:
类定义:
class SummaryRanges {
public SummaryRanges() {} // 初始化
public void addNum(int val) {} // 添加新整数
public int[][] getIntervals() {} // 返回区间数组(如 [[1,3],[5,7]])
}
输入/输出约束:
- 操作调用次数 ≤
3×10^4; getIntervals调用次数 ≥10次(需高效实现);- 区间输出格式:每个区间
[start, end]满足start ≤ end,且全局按start升序排列。
解题思路
题目要求设计一个数据结构,能够高效地将输入的整数合并成不相交区间,并支持查询当前区间集合。核心思路如下:
- 数据结构选择:使用
TreeMap存储区间,以区间左端点为键,右端点为值。TreeMap支持高效查询(O(log n))和有序遍历。 - 添加数值逻辑:
- 检查重复:通过
floorEntry(val)查找小于等于val的最大区间,若该区间的右端点≥val,说明val已包含在区间中。 - 合并左区间:若左邻居的右端点+1等于
val,则扩展该区间右端点至val。 - 合并右区间:若右邻居的左端点-1等于
val,则删除原右区间,插入新区间[val, 原右端点]。 - 合并左右区间:若
val同时与左右邻居相邻,则合并左右区间为一个新区间。 - 独立区间:若无法合并,插入新区间
[val, val]。
- 检查重复:通过
- 查询区间逻辑:直接遍历
TreeMap,按左端点升序输出所有区间。
代码实现(Java版)🔥点击下载源码
class SummaryRanges {
private TreeMap<Integer, Integer> intervals; // 存储区间:key=左端点, value=右端点
public SummaryRanges() {
intervals = new TreeMap<>();
}
public void addNum(int val) {
// 检查是否已存在于区间
Map.Entry<Integer, Integer> left = intervals.floorEntry(val);
if (left != null && left.getValue() >= val)
return;
// 检查左右邻居
boolean mergeLeft = (left != null && left.getValue() + 1 == val);
boolean mergeRight = intervals.containsKey(val + 1);
// 合并左右邻居
if (mergeLeft && mergeRight) {
int rightEnd = intervals.get(val + 1);
intervals.put(left.getKey(), rightEnd);
intervals.remove(val + 1);
}
// 只合并左邻居
else if (mergeLeft) {
intervals.put(left.getKey(), val);
}
// 只合并右邻居
else if (mergeRight) {
int rightEnd = intervals.get(val + 1);
intervals.remove(val + 1);
intervals.put(val, rightEnd);
}
// 独立区间
else {
intervals.put(val, val);
}
}
public int[][] getIntervals() {
int[][] res = new int[intervals.size()][2];
int idx = 0;
for (var entry : intervals.entrySet()) {
res[idx][0] = entry.getKey();
res[idx][1] = entry.getValue();
idx++;
}
return res;
}
}
代码说明
- 初始化:
TreeMap初始化用于存储区间。 - addNum方法:
- 去重检查:
floorEntry(val)查找可能包含val的左邻居区间。 - 合并逻辑:
- 同时合并左右邻居:删除右邻居,扩展左邻居的右端点。
- 合并左邻居:直接扩展左邻居的右端点。
- 合并右邻居:删除原右邻居,插入以
val为左端点的区间。 - 无法合并:插入新区间
[val, val]。
- 去重检查:
- getIntervals方法:遍历
TreeMap,按左端点升序输出所有区间。 - 复杂度:
- 时间复杂度:
addNum()为O(log n)(TreeMap操作),getIntervals()为O(n)。 - 空间复杂度:
O(n),存储所有区间。
- 时间复杂度:
提交详情(执行用时、内存消耗)

367

被折叠的 条评论
为什么被折叠?



