LeetCode 435. 无重叠区间
题目描述


题意分析
每个区间只能整体保留或删除,不能通过合并改变它。总区间数固定,因此删除最少区间,等价于保留最多互不重叠的区间。
题目允许端点相接,后一段开始等于前一段结束时仍能保留。为了尽量给后续区间留出位置,每次应从当前能接上的区间里,优先选择结束最早的一个;按右端点升序排序就能依次作出这个选择。
解法:按右端点排序的贪心
核心思路
[!blue]
固定已经保留的区间,设接下来最早结束的可选区间为
a,某个最优方案接下来选择了b。由于a、b都能接上前缀,且a的结束位置不晚于b,将b换成a后,原本接在b后面的区间仍然都能接上。替换不减少保留数量,说明一定存在采用这次贪心选择的最优方案;对后续区间重复这一过程即可。排序后,
end表示最后一个已保留区间的右端点,removed表示扫描过程中删除的区间数。已保留的区间互不重叠,所以新区间只需与最后一个比较:
- 若
start < end,新区间发生重叠。它的结束位置不会比已保留区间更早,删除它并保留原来的end,更有利于接入后续区间。- 若
start >= end,新区间能够接入,而且它是尚未扫描的可接区间中结束最早的一个,保留它并更新end。每个区间都恰好被保留或删除一次。贪心保证保留数量最多,因此直接累计得到的
removed就是最少删除数。右端点相同的区间无需额外规定排序顺序:能接入的任一个留下的结束位置都相同。
解题步骤
- 按右端点升序排序,用第一个区间初始化
end。- 从第二个区间开始扫描:若
start < end,说明发生重叠,删除数加一;由于当前区间结束得不更早,继续保留原区间。- 若
start >= end,两个区间不重叠,保留当前区间并更新end。端点相接允许共存,所以这里必须用>=。- 扫描结束后返回删除数。
代码实现
class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
Arrays.sort(intervals, (a, b) -> Integer.compare(a[1], b[1]));
int removed = 0;
int end = intervals[0][1];
for (int i = 1; i < intervals.length; i++) {
if (intervals[i][0] < end) {
// 冲突时丢弃当前区间,保留结束更早的原边界。
removed++;
} else {
end = intervals[i][1];
}
}
return removed;
}
}
import "sort"
func eraseOverlapIntervals(intervals [][]int) int {
sort.Slice(intervals, func(i, j int) bool {
return intervals[i][1] < intervals[j][1]
})
removed := 0
end := intervals[0][1]
for i := 1; i < len(intervals); i++ {
if intervals[i][0] < end {
// 冲突时丢弃当前区间,保留结束更早的原边界。
removed++
} else {
end = intervals[i][1]
}
}
return removed
}
复杂度分析
- 时间复杂度:$O(n \log n)$,排序是 $O(n \log n)$,之后只做一次线性扫描,每个区间常数次比较与赋值,排序占主导。
- 空间复杂度:贪心扫描为 $O(1)$;若计入标准库排序,Java 的对象数组排序需要 $O(n)$ 辅助空间,Go 排序需要 $O(\log n)$ 调用栈。
关键点总结
[!green]
- 总数固定,把「删除最少」转成「保留最多」,再用最早结束的区间给后续选择留出空间。
- 当前贪心依赖右端点升序,交换论证保证每次选取都能延续到某个最优方案。
end记录最后保留的结束位置,removed累计删除数;冲突时只增加计数,不改结束位置。- 本题端点相接不算重叠,条件是
start >= end;边界口径必须从题意推出。
易错点总结
[!yellow]
- 只把排序改成按左端点升序,再无条件保留最先遇到的区间,可能留下很长的区间并挡住多个短区间;这不符合本解法的贪心依据。
- 接入条件不能写成
start > end,否则会把允许的端点相接误判成重叠。- 保留新区间时必须更新
end;删除冲突区间时必须保留旧end,否则后续判断会基于错误边界。- 区间端点可以是负数,
end应从第一个实际区间初始化,不能默认设为零。- 题目保证至少有一个区间,所以可以访问
intervals[0];只有一个区间时循环不执行,删除数自然为零。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 452. 用最少数量的箭引爆气球 | 中等 | 同样按区间右端点贪心,原题选最少刺点覆盖全部区间,本题选最多互不重叠区间。 |
| 56. 合并区间 | 中等 | 原题合并重叠区间保留并集,本题通过删除部分原区间消除重叠。 |
| 646. 最长数对链 | 中等 | 按结束位置判断区间重叠并进行贪心选择;本题保留尽可能多的不重叠区间,该题将数对连接视为不重叠区间选择。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!