LeetCode 759. 员工空闲时间
题目描述
题意分析
日程记录的是员工忙碌的时间,要求找出所有员工都空闲的有限正长度区间,并按时间顺序返回。只要有一个员工忙碌,该时段就不能算共同空闲,因此应先求所有忙碌区间的并集,再找并集相邻部分之间的空隙。
解法:拉平后排序并合并忙碌段
核心思路
[!blue]
将所有员工的忙碌区间放入同一列表,按起点从小到大排序。扫描时,用
curEnd保存已经处理的忙碌区间能到达的最右端点,也就是当前最后一段忙碌并集的结束位置。若下一区间的起点
start > curEnd,已处理的区间都不会晚于curEnd结束,未处理的区间又都不会早于start开始,所以中间的[curEnd, start]没有任何人忙碌,正是一个共同空闲区间。若
start <= curEnd,新区间与最后一段忙碌时间重叠或相接,不产生正长度空隙。两种情况都更新curEnd = max(curEnd, end):新区间可能延长覆盖,也可能完全被已有区间包含,不能让覆盖边界向左退。每个有限空闲区间都位于相邻的忙碌并集之间,扫描到后一个忙碌区间时就会被发现,因此不会遗漏。第一段之前和最后一段之后的空闲向无穷延伸,不属于题目要求的有限区间。
解题步骤
- 收集所有忙碌区间到新列表;若没有区间,返回空结果。
- 按起点排序,用第一段的结束时间初始化
curEnd。- 从第二段开始扫描,若起点严格大于
curEnd,添加空闲区间[curEnd, start]。- 用当前结束时间更新最右覆盖端点,继续处理下一段。
嵌套区间不会缩短已有覆盖;首尾相接时只共享一个端点,没有正长度空闲。扫描过程中按时间发现空隙,结果自然已经有序,无需再排序。
代码实现
class Solution {
// 单个员工区间已按时间有序,跨员工合并后再统一排序即可形成一条扫描线。
public List<Interval> employeeFreeTime(List<List<Interval>> schedule) {
List<Interval> all = new ArrayList<>();
for (List<Interval> employee : schedule) {
all.addAll(employee);
}
List<Interval> res = new ArrayList<>();
if (all.isEmpty()) {
return res;
}
all.sort((a, b) -> Integer.compare(a.start, b.start));
int curEnd = all.get(0).end;
for (int i = 1; i < all.size(); i++) {
Interval interval = all.get(i);
// 只输出严格正长度的空隙,接触端点不算空闲段
if (interval.start > curEnd) {
res.add(new Interval(curEnd, interval.start));
}
// 包含关系不能让覆盖右端倒退,出现空隙后也要更新
curEnd = Math.max(curEnd, interval.end);
}
return res;
}
}
import "sort"
func employeeFreeTime(schedule [][]*Interval) []*Interval {
// 单个员工区间已按时间有序,跨员工合并后再统一排序即可形成一条扫描线。
all := make([]*Interval, 0)
for _, employee := range schedule {
all = append(all, employee...)
}
res := make([]*Interval, 0)
if len(all) == 0 {
return res
}
sort.Slice(all, func(i, j int) bool {
return all[i].Start < all[j].Start
})
curEnd := all[0].End
for i := 1; i < len(all); i++ {
interval := all[i]
// 只输出严格正长度的空隙,接触端点不算空闲段
if interval.Start > curEnd {
res = append(res, &Interval{Start: curEnd, End: interval.Start})
}
// 包含关系不能让覆盖右端倒退,出现空隙后也要更新
if interval.End > curEnd {
curEnd = interval.End
}
}
return res
}
复杂度分析
- 时间复杂度:$O(N\log(N+1))$,N 为全部忙碌区间数量。
- 空间复杂度:$O(N)$,拉平引用列表与排序辅助。
关键点总结
[!green]
- curEnd 跟踪最新覆盖边界,跨过空隙后已属于新的忙碌连通段。
- 首尾相接没有正长度空隙。
- 排序的是新建的引用列表,不改变员工原日程顺序,也不修改区间端点。
易错点总结
[!yellow]
- 直接用当前结束时间覆盖,会在嵌套区间后造出假空隙。
- 条件用大于等于,会输出零长度区间。
- 只按每个人内部顺序拼接,不能保证全局有序。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 56. 合并区间 | 中等 | 先合并所有忙碌区间,再取相邻合并区间之间的有限空隙。 |
| 23. 合并 K 个升序链表 | 困难 | 各员工日程内部有序,可通过多路归并按起点依次处理,不必重新排序所有区间。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!