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.

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.

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

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.

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

Example 1:

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

这道题咋一看意思好理解,但是要解出这道题还是需要有条理的思路。

1.首先我们需要定义两个set<int,int>   s1,s2, 来分别存储没有交集(该区间被覆盖一次)、有一层交集(覆盖两次)的区间。

2.如果每次预订的区间与之前的所有区间没有交集(if(Start>=a.second || End<=a.first)),那么将其直接加入s1中;如果与map中某个区间有交集,那么将公共区间加入有一层交集的s2中。

3.最后每次先在s2中查看是否与当前区间有重叠,若有直接返回false,若无则查看s1中是否有与之重叠的区间,若有则更新s2,若无则更新s1。

如下为代码实现:

class MyCalendarTwo{
public :
    MyCalendarTwo(){};
    bool book(int Start,int End){
        for(auto a:s2){
            if(Start>=a.second || End<=a.first) continue;
            else return false;
        }
        for(auto a:s1){
            if(Start>=a.second || End<=a.first) continue;
            else 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,来统计当前的次数。我们使用map具有自动排序的功能,所以我们遍历的时候就是按时间顺序的,最先遍历到的一定是一个起始时间,所以加上其映射值,一定是个正数。

举例:我们现在假设map中已经加入了一个区间[3, 5)了,那么我们就有下面的映射:

3 -> 1

5 -> -1

假如我们此时要加入的区间为[6, 8)的话,那么在遍历到6的时候,前面经过3和5,分别加1减1,那么cnt又重置为0了,而后面的6和8也是分别加1减1,还是0。那么加入我们新加入的区间为[3, 8]时,那么此时的映射为:

3 -> 2

5 -> -1

8 -> -1

那么我们最先遍历到3,cnt为2,没有超过3,我们知道此时有两个事件有重叠,是允许的。然后遍历5和8,分别减去1,最终又变成0了,始终cnt没有超过2,所以是符合题意的。如果此时我们再加入一个新的区间[1, 4),那么此时的映射为:

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;
};



猜你喜欢

转载自blog.csdn.net/did_you/article/details/79326257
my