英文原文
You are implementing a program to use as your calendar. We can add a new event if adding the event will not cause a triple booking.
A triple booking happens when three events have some non-empty intersection (i.e., some moment is common to all the three events.).
The event can be represented as a pair of integers start and end that represents a booking on the half-open interval [start, end), the range of real numbers x such that start <= x < end.
Implement the MyCalendarTwo class:
MyCalendarTwo()Initializes the calendar object.boolean book(int start, int end)Returnstrueif the event can be added to the calendar successfully without causing a triple booking. Otherwise, returnfalseand do not add the event to the calendar.
Example 1:
Input ["MyCalendarTwo", "book", "book", "book", "book", "book", "book"] [[], [10, 20], [50, 60], [10, 40], [5, 15], [5, 10], [25, 55]] Output [null, true, true, true, false, true, true] Explanation MyCalendarTwo myCalendarTwo = new MyCalendarTwo(); myCalendarTwo.book(10, 20); // return True, The event can be booked. myCalendarTwo.book(50, 60); // return True, The event can be booked. myCalendarTwo.book(10, 40); // return True, The event can be double booked. myCalendarTwo.book(5, 15); // return False, The event ca not be booked, because it would result in a triple booking. myCalendarTwo.book(5, 10); // return True, The event can be booked, as it does not use time 10 which is already double booked. myCalendarTwo.book(25, 55); // return True, The event can be booked, as the time in [25, 40) will be double booked with the third event, the time [40, 50) will be single booked, and the time [50, 55) will be double booked with the second event.
Constraints:
0 <= start < end <= 109- At most
1000calls will be made tobook.
中文题目
实现一个 MyCalendar 类来存放你的日程安排。如果要添加的时间内不会导致三重预订时,则可以存储这个新的日程安排。
MyCalendar 有一个 book(int start, int end)方法。它意味着在 start 到 end 时间内增加一个日程安排,注意,这里的时间是半开区间,即 [start, end), 实数 x 的范围为, start <= x < end。
当三个日程安排有一些时间上的交叉时(例如三个日程安排都在同一时间内),就会产生三重预订。
每次调用 MyCalendar.book方法时,如果可以将日程安排成功添加到日历中而不会导致三重预订,返回 true。否则,返回 false 并且不要将该日程安排添加到日历中。
请按照以下步骤调用MyCalendar 类: MyCalendar cal = new MyCalendar(); MyCalendar.book(start, end)
示例:
MyCalendar(); MyCalendar.book(10, 20); // returns true MyCalendar.book(50, 60); // returns true MyCalendar.book(10, 40); // returns true MyCalendar.book(5, 15); // returns false MyCalendar.book(5, 10); // returns true MyCalendar.book(25, 55); // returns true 解释: 前两个日程安排可以添加至日历中。 第三个日程安排会导致双重预订,但可以添加至日历中。 第四个日程安排活动(5,15)不能添加至日历中,因为它会导致三重预订。 第五个日程安排(5,10)可以添加至日历中,因为它未使用已经双重预订的时间10。 第六个日程安排(25,55)可以添加至日历中,因为时间 [25,40] 将和第三个日程安排双重预订; 时间 [40,50] 将单独预订,时间 [50,55)将和第二个日程安排双重预订。
提示:
- 每个测试用例,调用
MyCalendar.book函数最多不超过1000次。 - 调用函数
MyCalendar.book(start, end)时,start和end的取值范围为[0, 10^9]。
通过代码
官方题解
方法一:暴力法
维护一重预订列表和双重预订列表。当预订一个新的日程安排 [start, end) 时,如果它与双重预订列表冲突,则会产生三重预定。
算法:
- 当且仅当事件
[s1, e1)在另一个事件[s2, e2)结束后开始,两个事件不冲突,也就是说满足e1<=s2或e2<=s1时,两个事件不冲突。这意味着当s1<e2和s2<e1时,事件发生冲突。 - 如果新的日程安排与双重预订冲突,则返回
false。否则,我们会将与一重预定列表冲突的时间添加到双重预订列表中,并将该预定添加到一重预定列表中。
[ ]class MyCalendarTwo: def __init__(self): self.calendar = [] self.overlaps = [] def book(self, start, end): for i, j in self.overlaps: if start < j and end > i: return False for i, j in self.calendar: if start < j and end > i: self.overlaps.append((max(start, i), min(end, j))) self.calendar.append((start, end)) return True
[ ]public class MyCalendarTwo { List<int[]> calendar; List<int[]> overlaps; MyCalendarTwo() { calendar = new ArrayList(); } public boolean book(int start, int end) { for (int[] iv: overlaps) { if (iv[0] < end && start < iv[1]) return false; } for (int[] iv: calendar) { if (iv[0] < end && start < iv[1]) overlaps.add(new int[]{Math.max(start, iv[0]), Math.min(end, iv[1])}); } calendar.add(new int[]{start, end}); return true; } }
复杂度分析
- 时间复杂度:$O(N^2)$。$N$ 指的是日程安排的数量。对于每个新的日程安排,我们会遍历已预定的每个日程安排,以决定是否可以预订新的日程安排。这需要 $\sum_k^N O(k) = O(N^2)$ 的时间。
- 空间复杂度:$O(N)$,
calendar所使用的空间。
方法二:边界计数
算法:
- 当我们预定一个新的日程安排
[start, end),则执行delta[start]++和delta[end]--。其中delta是按照key值从小到大排序的结构,我们用active来记录当前正在进行的日程安排数,当active>=3时,说明产生了三重预定。 - 此方法不包括 python 实现,因为没有 TreeMap。[ ]
class MyCalendarTwo { TreeMap<Integer, Integer> delta; public MyCalendarTwo() { delta = new TreeMap(); } public boolean book(int start, int end) { delta.put(start, delta.getOrDefault(start, 0) + 1); delta.put(end, delta.getOrDefault(end, 0) - 1); int active = 0; for (int d: delta.values()) { active += d; if (active >= 3) { delta.put(start, delta.get(start) - 1); delta.put(end, delta.get(end) + 1); if (delta.get(start) == 0) delta.remove(start); return false; } } return true; } }
复杂度分析
- 时间复杂度:$O(N^2)$。$N$ 指的是日程安排的数量。对于每个新的日程安排,我们遍历
delta需要 $O(N)$ 的时间 - 空间复杂度:$O(N)$,
delta所使用的空间。
统计信息
| 通过次数 | 提交次数 | AC比率 |
|---|---|---|
| 4414 | 8754 | 50.4% |
提交历史
| 提交时间 | 提交结果 | 执行时间 | 内存消耗 | 语言 |
|---|
相似题目
| 题目 | 难度 |
|---|---|
| 我的日程安排表 I | 中等 |
| 我的日程安排表 III | 困难 |