We are given a list schedule
of employees, which represents the working time for each employee.
Each employee has a list of non-overlapping Intervals
, and these intervals are in sorted order.
Return the list of finite intervals representing common, positive-length free time for all employees, also in sorted order.
(Even though we are representing Intervals
in the form [x, y]
, the objects inside are Intervals
, not lists or arrays. For example, schedule[0][0].start = 1
, schedule[0][0].end = 2
, and schedule[0][0][0]
is not defined). Also, we wouldn't include intervals like [5, 5] in our answer, as they have zero length.
Example 1:
Input: schedule = [[[1,2],[5,6]],[[1,3]],[[4,10]]] Output: [[3,4]] Explanation: There are a total of three employees, and all common free time intervals would be [-inf, 1], [3, 4], [10, inf]. We discard any intervals that contain inf as they aren't finite.
Example 2:
Input: schedule = [[[1,3],[6,7]],[[2,4]],[[2,5],[9,12]]] Output: [[5,6],[7,9]]
Constraints:
1 <= schedule.length , schedule[i].length <= 50
0 <= schedule[i].start < schedule[i].end <= 10^8
题目给定一个二维数组schedule用来表示所有员工的工作时间表,每个员工拥有一组工作时间段,其中每个工作时间段是用自定义的类Interval中的Interval.start和Interval.end来表示工作的起始和结束时间的。因此二维数组schedule可以表示为:[[Interval, ...], [Interval, ...], ..., [Interval, ...]],其中每个员工的各个工作时间段是没有重叠且是按顺序排列好的。要求找出所有员工的公共空闲时间段(即没有任何一位员工在工作),并按顺序排列好返回各个时间段。注意,类似[5, 5]这样的时间段不算有效时间段。
这题要是把员工工作时间换成会议时间,那这道题其实就是253. Meeting Rooms II的拓展。题目的问法可以变成,给定一个二维数组schedule用来表示所有部门的会议时间表,每个部门拥有一组会议时间段,其中每个会议时间段是用自定义的类Interval中的Interval.start和Interval.end来表示会议的起始和结束时间的。因此二维数组schedule可以表示为:[[Interval, ...], [Interval, ...], ..., [Interval, ...]],其中每个部门的各个工作时间段是没有重叠且是按顺序排列好的。现在有一个超大会议室允许多部门同时开会,只要有部门有会议的起始时间到了就可以进入会议室开会。要求找出会议室的空闲时间段(即没有任何一个部门在里面开会的时间段),并按顺序排列好返回各个空闲时间段。
因此本题解法可以延续253. Meeting Rooms II的基本思路:把所有时间区间按起始时间大小排个序,然后遍历所有时间区间,把已遍历的时间段的结束时间放入一个优先级队列中,比较当前时间区间的起始时间与队列中最大的结束时间。
然而,这道题与253. Meeting Rooms II不同的是:给定的时间段是一个二维数组,每一行已经是排好序的了,可以利用23. Merge k Sorted Lis相似的合并排序算法,对所有时间段以起始时间从小到大进行遍历(省去先排序后遍历的过程)。也就是把数组schedule的每一行第一个时间段都放入一个优先级队列,每次弹出的就是起始时间最小的那个时间段,然后进行处理(判断是否有空闲时间区间),最后把该时间段所在行的下一个时间段(如果没到行末尾的话)再放入队列中。另外由于求的不是最多有少员工在同时工作,而是只需判断当前时间段开始之前是否有空闲时间段,因此不需要像253. Meeting Rooms II那样用一个优先级队列来存入已经开始的工作时间段的结束时间,只需维护一个变量来表示已经开始的所有时间段中结束时间最晚的那个,这样就可以比较当前时间段的开始时间和它之前所有时间段的最晚结束时间,如果当前时间段的开始时间大于它之前所有时间段的最晚结束时间,那么二者的时间差的时间段就是所有员工的空闲时间。按以上方法遍历所有时间段,最后得到的就是所有的空闲时间段并且是排好序的。
"""
# 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]':
m = len(schedule)
pq=[]
for i in range(m):
heapq.heappush(pq, (schedule[i][0].start, schedule[i][0].end, i, 0))
lastEnd = -1
res = []
while len(pq) > 0:
(start, end, i, j) = heapq.heappop(pq)
if lastEnd > 0 and start > lastEnd:
res.append(Interval(lastEnd, start))
lastEnd = max(lastEnd, end)
if j < len(schedule[i]) - 1:
j += 1
heapq.heappush(pq, (schedule[i][j].start, schedule[i][j].end, i, j))
return res