LeetCode 759. 员工空闲时间

759. 员工空闲时间

给定员工的 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。

注:

  1. schedule 和 schedule[i] 为长度范围在 [1, 50]的列表。
  2. 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)。
  • 16
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值