LeetCode – 759. Employee Free Time

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.

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]]

(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.

Note:

schedule and schedule[i] are lists with lengths in range [1, 50].
0 <= schedule[i].start < schedule[i].end <= 10^8.

题意:

输入给出数组“schedule”来表示每个员工的工作时间段,例如
schedule = [
[(1,2), (5,6)],
[(1,3)],
[(4,10)],
]

表示第一个员工1点到2点工作、5点到6点工作,第二个员工1点到3点工作,第三个员工4点到10点工作。请找出所有员工都休息的时间段。

例子1:
输入: schedule = [[(1,2),(5,6)],[(1,3)],[(4,10)]]
输出: [(3,4)]

例子2:
输入: schedule =[[(1,3),(6,7)],[(2,4)],[(2,5),(9,12)]]
输出: [(5,6),(7,9)]

其它限制条件:
员工个数不超过50
每个员工的工作时间段不超过50
每个时间段的开始和结束时间在[0, 10^8]

分析:

从题目中限制条件我们可以看到,每个时间段开始和结束的时间点有10^8之多,所以为了能在限定的时间内完成,我们就不能设计基于所有可能时间点的算法(例如,遍历所有可能时间点,然后查找是否有员工在此时间点工作)。而所有员工的最多时间段只有2500个,所以我们设计的算法要建立在直接应用时间段上。

确认设计方向后,我们就可以认识到,如果我们能够把所有员工的工作时间段“merge”到一起,那找起所有员工都休息的时间段就要容易很多。例如第一个例子(参见下图),我们合并所有员工工作的时间段后就可以很显然的看出只有在3点和4点之前是所有员工都休息的。

那么,下面的问题就是如何快速的把所有员工的工作时间段合并起来了。一个很自然的想法就是将所有工作时间段按开始时间排序,然后一个一个的合并起来。

还是那第一个例子来示范,将所有的时间段排序后我们得到[(1,2), (1,3), (4,10), (5,6)]],那么我们就可以从头遍历所有的时间段看看它能不能和下面一个合并。例如时间段(1,2)的结束时间大于时间段(1,3)的开始时间,它们中间有重叠,能够合并成(1,3)。同理,时间段(4,10)和(5,6)能合并成(4,10),但时间段(1,3)和(4,10)中间没有重叠,不能合并。这两个时间段中间的空隙,从时间段(1,3)的结束时间到(4,10)的开始时间即时间段(3,4),就是员工休息时间。

好,综上所述,如果我们有n个时间段,我们需要O(nlogn)的时间来排序,再用O(n)的时间来合并时间段并找出所有员工都休息的空档,所以总共的时间复杂度就是O(nlogn)。

public class LeetCode_759 {
	
	public static class Interval{
		int begin;
		int end;
		Interval() {
			begin = 0;
			end = 0;
		}
		Interval(int b, int e) {
			begin = b;
			end = e;
		}
		
	}
	
	public static List<Interval> employeeFreeTime(List<List<Interval>> schedule){
		List<Interval> freeTime = new ArrayList<>();
		List<Interval> intervals = new ArrayList<>();
		for (List<Interval> list : schedule) {
			for (Interval interval : list) {
				intervals.add(interval);
			}
		}
		intervals.sort(new Comparator<Interval>() {
			@Override
			public int compare(Interval o1, Interval o2) {
				if (o1.begin >= o2.begin) {
					return 1;
				}else {
					return -1;
				}
			}
		});
		
		Interval cur = null;
		for (Interval interval : intervals) {
			if (null == cur) {
				cur = new Interval(interval.begin, interval.end);
				continue;
			}
			if (cur.end >= interval.begin) {
				cur.end = Math.max(cur.end, interval.end);
				continue;
			}
			freeTime.add(new Interval(cur.end, interval.begin));
			cur = interval;
		}
		return freeTime;
	}

	public static void main(String[] args) {
		List<List<Interval>> schedule = new ArrayList<>();
		List<Interval> list = new ArrayList<>();
		List<Interval> list1 = new ArrayList<>();
		List<Interval> list2 = new ArrayList<>();
		list.add(new Interval(1, 2));
		list.add(new Interval(5, 6));
		schedule.add(list);
		list1.add(new Interval(1, 3));
		list2.add(new Interval(4, 10));
		schedule.add(list1);
		schedule.add(list2);
		
		List<Interval> freeTime = employeeFreeTime(schedule);
		for (Interval interval : freeTime) {
			System.out.println(interval.begin + "--" + interval.end);
		}
	}

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值