给定员工的 schedule
列表,表示每个员工的工作时间。
每个员工都有一个非重叠的时间段 Intervals
列表,这些时间段已经排好序。
返回表示 所有 员工的 共同,正数长度的空闲时间 的有限时间段的列表,同样需要排好序。
示例 1:
输入:schedule = [[[1,2],[5,6]],[[1,3]],[[4,10]]] 输出:[[3,4]] 解释: 共有 3 个员工,并且所有共同的 空间时间段是 [-inf, 1], [3, 4], [10, inf]。 我们去除所有包含 inf 的时间段,因为它们不是有限的时间段。
示例 2:
输入:schedule = [[[1,3],[6,7]],[[2,4]],[[2,5],[9,12]]] 输出:[[5,6],[7,9]]
(尽管我们用 [x, y]
的形式表示 Intervals
,内部的对象是 Intervals
而不是列表或数组。例如,schedule[0][0].start = 1, schedule[0][0].end = 2
,并且 schedule[0][0][0]
是未定义的)
而且,答案中不包含 [5, 5] ,因为长度为 0。
注:
schedule
和schedule[i]
为长度范围在[1, 50]
的列表。0 <= schedule[i].start < schedule[i].end <= 10^8
。
注:输入类型于 2019 年 4 月 15 日 改变。请重置为默认代码的定义以获取新方法。
提示 1
Take all the intervals and do an "events" (or "line sweep") approach - an event of (x, OPEN) increases the number of active intervals, while (x, CLOSE) decreases it. Processing in sorted order from left to right, if the number of active intervals is zero, then you crossed a region of common free time.
解法1:事件处理 + 扫描线 line sweep + 差分 + 排序
用扫描线进行线性扫描,其实就是统计某一时刻,正在工作的人数。
如果某个区间与任一区间重叠,则该区间不会出现在答案中。所以我们可以将问题转换为:给定一组区间,找出所有员工都不包含的区间。
我们可以使用区间问题中的 “事件” 方法。对于每个区间 [s, e],我们可以看作有两个事件:
- 当 time = s 时,balance++;
- 当 time = e 时,balance--。
我们只关心 balance == 0 的区间。
算法:
对于每个区间,创建如上所述的两个事件,并对事件进行排序。在事件 t 发生的每个事件,如果 balance == 0,则说明 [prev,t] 是所有员工都不包含的区间,其中 prev 是 t 的前一个值。
Java版:
/*
// Definition for an Interval.
class Interval {
public int start;
public int end;
public Interval() {}
public Interval(int _start, int _end) {
start = _start;
end = _end;
}
};
*/
class Solution {
public List<Interval> employeeFreeTime(List<List<Interval>> schedule) {
List<int[]> events = new ArrayList<>();
for (List<Interval> i : schedule) {
for (Interval j : i) {
events.add(new int[]{j.start, 1});
events.add(new int[]{j.end, -1});
}
}
Collections.sort(events, new Comparator<int[]>() {
public int compare(int[] a, int[] b) {
return a[0] != b[0] ? a[0] - b[0] : b[1] - a[1];
}
});
List<Interval> ans = new ArrayList<>();
int prev = -1;
int balance = 0;
for (int[] event: events) {
if (balance == 0 && prev >= 0) {
ans.add(new Interval(prev, event[0]));
}
balance += event[1];
prev = event[0];
}
return ans;
}
}
Python3版:
"""
# Definition for an Interval.
class Interval:
def __init__(self, start: int = None, end: int = None):
self.start = start
self.end = end
"""
class Solution:
def employeeFreeTime(self, schedule: '[[Interval]]') -> '[Interval]':
OPEN = 0
CLOSE = 1
events = []
for i in schedule:
for j in i:
events.append([j.start, OPEN])
events.append([j.end, CLOSE])
events.sort()
prev = -1
balance = 0
ans = []
for time, command in events:
if balance == 0 and prev > -1:
ans.append(Interval(prev, time))
balance += 1 if command == 0 else -1
prev = time
return ans
复杂度分析
- 时间复杂度:O(ClogC),其中 C 是所有员工的区间数。
- 空间复杂度:O(C)。