[LeetCode] 731. My Calendar II 个人日历之二

 

Implement a MyCalendarTwo class to store your events. A new event can be added if adding the event will not cause a triple booking.html

Your class will have one method, book(int start, int end). Formally, this represents a booking on the half open interval [start, end), the range of real numbers x such that start <= x < end.git

triple booking happens when three events have some non-empty intersection (ie., there is some time that is common to all 3 events.)github

For each call to the method MyCalendar.book, return 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.app

Your class will be called like this: MyCalendar cal = new MyCalendar(); MyCalendar.book(start, end)post

Example 1:this

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
Explanation: 
The first two events can be booked.  The third event can be double booked.
The fourth event (5, 15) can't be booked, because it would result in a triple booking.
The fifth event (5, 10) can be booked, as it does not use time 10 which is already double booked.
The sixth event (25, 55) 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.

 

Note:url

  • The number of calls to MyCalendar.book per test case will be at most 1000.
  • In calls to MyCalendar.book(start, end)start and end are integers in the range [0, 10^9].

 

这道题是 My Calendar I 的拓展,以前那道题说是不能有任何的重叠区间,而这道题说最多容忍两个重叠区域,注意是重叠区域,不是事件。好比事件 A,B,C 互不重叠,可是有一个事件D,和这三个事件都重叠,这样是能够的,由于重叠的区域最多只有两个。因此关键仍是要知道具体的重叠区域,若是两个事件重叠,那么重叠区域就是它们的交集,求交集的方法是两个区间的起始时间中的较大值,到结束时间中的较小值。能够用一个 TreeSet 来专门存重叠区间,再用一个 TreeSet 来存完整的区间,那么思路就是,先遍历专门存重叠区间的 TreeSet,由于能在这里出现的区间,都已是出现两次了,若是当前新的区间跟重叠区间有交集的话,说明此时三个事件重叠了,直接返回 false。若是当前区间跟重叠区间没有交集的话,则再来遍历完整区间的集合,若是有交集的话,那么应该算出重叠区间而且加入放重叠区间的 TreeSet 中。最后记得将新区间加入完整区间的 TreeSet 中,参见代码以下:spa

 

解法一:code

class MyCalendarTwo {
public:
    MyCalendarTwo() {}
    
    bool book(int start, int end) {
        for (auto &a : s2) {
            if (start >= a.second || end <= a.first) continue;
            return false;
        }
        for (auto &a : s1) {
            if (start >= a.second || end <= a.first) continue;
            s2.insert({max(start, a.first), min(end, a.second)});
        }
        s1.insert({start, end});
        return true;
    }

private:
    set<pair<int, int>> s1, s2;
};

 

下面这种方法至关的巧妙,创建一个时间点和次数之间的映射,规定遇到起始时间点,次数加1,遇到结束时间点,次数减1。那么首先更改新的起始时间 start 和结束时间 end 的映射,start 对应值增1,end 对应值减1。而后定义一个变量 cnt,来统计当前的次数。使用 TreeMap 具备自动排序的功能,因此遍历的时候就是按时间顺序的,最早遍历到的必定是一个起始时间,因此加上其映射值,必定是个正数。若是此时只有一个区间,就是刚加进来的区间的话,那么首先确定遍历到 start,那么 cnt 此时加1,而后就会遍历到 end,那么此时 cnt 减1,最后下来 cnt 为0,没有重叠。仍是用具体数字来讲吧,如今假设 TreeMap 中已经加入了一个区间 [3, 5) 了,就有下面的映射:orm

3 -> 1

5 -> -1

假如此时要加入的区间为 [3, 8) 的话,则先对3和8分别加1减1,此时的映射为:

3 -> 2

5 -> -1

8 -> -1

最早遍历到3,cnt 为2,没有超过3,此时有两个事件有重叠,是容许的。而后遍历5和8,分别减去1,最终又变成0了,始终 cnt 没有超过2,因此是符合题意的。若是此时再加入一个新的区间 [1, 4),则先对1和4分别加1减1,那么此时的映射为:

1 -> 1

3 -> 2

4 -> -1

5 -> -1

8 -> -1

先遍历到1,cnt为1,而后遍历到3,此时 cnt 为3了,那么就知道有三个事件有重叠区间了,因此这个新区间是不能加入的,须要还原其 start 和 end 作的操做,把 start 的映射值减1,end 的映射值加1,而后返回 false。不然没有三个事件有共同重叠区间的话,返回 true 便可,参见代码以下:

 

解法二:

class MyCalendarTwo {
public:
    MyCalendarTwo() {}
    
    bool book(int start, int end) {
        ++freq[start];
        --freq[end];
        int cnt = 0;
        for (auto f : freq) {
            cnt += f.second;
            if (cnt == 3) {
                --freq[start];
                ++freq[end];
                return false;
            }
        }
        return true;
    }

private:
    map<int, int> freq;
};

 

Github 同步地址:

https://github.com/grandyang/leetcode/issues/731

 

相似题目:

My Calendar I

 

参考资料:

https://leetcode.com/problems/my-calendar-ii/

https://leetcode.com/problems/my-calendar-ii/discuss/109550/Simple-AC-by-TreeMap

https://leetcode.com/problems/my-calendar-ii/discuss/109522/Simplified-winner's-solution

https://leetcode.com/problems/my-calendar-ii/discuss/109519/JavaC%2B%2B-Clean-Code-with-Explanation

 

LeetCode All in One 题目讲解汇总(持续更新中...)

相关文章
相关标签/搜索