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



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章