持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情
题目描述
实现一个 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)将和第二个日程安排双重预订。
思路
昨天的每日一题是我的日程安排表 III。既然有III,那肯定还有I和II,今天就把II做了。
这题跟昨天很类似,题意是冲突导致双重是可以的,但是导致三重不行,遇到的为问题跟昨天都是类似的:
- 数组需要开的非常大,按照本题条件是10^9
- [start, end)的段上,每个值都加1的效率很低
采取的解法也是类似的:问题1,我们可以使用一个treeMap来记录起始位置,问题2,刚好是差分数组擅长的点。所以本题可以直接使用差分数组:用一个treeMap保存差分,没有就是0,每次book,start位置+1,end位置-1(因为end不包含,如果包含,就是end+1位置-1),这样,前k项的前缀和就是a[k]的值,每次book的时候,变化的只有[start,end]范围内的值,所以只要考虑这些值去更新max即可。
我们使用了一个max带来了常数级别的额外空间,但是在计算的时候,也节省了常数级别的时间,要不要这个设计都可以。
当然,有一个注意点是,如果某个book导致了三重预定,除了返回false之外,还要把这次book取消,因为这个WA了1次,看了好久才看出来问题。
Java版本代码
class MyCalendarTwo {
TreeMap<Integer, Integer> map;
int max;
public MyCalendarTwo() {
map = new TreeMap<>();
max = 0;
}
public boolean book(int start, int end) {
map.put(start, map.getOrDefault(start, 0) + 1);
map.put(end, map.getOrDefault(end, 0) - 1);
int temp = 0;
// 用于取消预定时,回退max
int preMax = max;
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
Integer key = entry.getKey();
// 相当于在[start,end)范围内+1,大于end的值肯定不会被影响
if (key > end) {
break;
}
temp += entry.getValue();
// 只有在[start,end)范围内的值才可能变化,判断这个范围内是否有值大于max,更新max就好
if (key >= start) {
if (temp > max) {
max = temp;
if (max >= 3) {
// 把本次预定取消
max = preMax;
map.put(start, map.getOrDefault(start, 0) - 1);
map.put(end, map.getOrDefault(end, 0) + 1);
return false;
}
}
}
}
return true;
}
}