加载中...
731-我的日程安排表 II(My Calendar II)
发表于:2021-12-03 | 分类: 中等
字数统计: 1.6k | 阅读时长: 7分钟 | 阅读量:

原文链接: https://leetcode-cn.com/problems/my-calendar-ii

英文原文

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) Returns true if the event can be added to the calendar successfully without causing a triple booking. Otherwise, return false and 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 1000 calls will be made to book.

中文题目

实现一个 MyCalendar 类来存放你的日程安排。如果要添加的时间内不会导致三重预订时,则可以存储这个新的日程安排。

MyCalendar 有一个 book(int start, int end)方法。它意味着在 startend 时间内增加一个日程安排,注意,这里的时间是半开区间,即 [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<=s2e2<=s1 时,两个事件不冲突。这意味着当 s1<e2s2<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 困难
上一篇:
730-统计不同回文子序列(Count Different Palindromic Subsequences)
下一篇:
732-我的日程安排表 III(My Calendar III)
本文目录
本文目录