[LeetCode] My Calendar I 個人日曆之一

 

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

Your class will have the 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.java

double booking happens when two events have some non-empty intersection (ie., there is some time that is common to both events.)數組

For each call to the method MyCalendar.book, return true if the event can be added to the calendar successfully without causing a double 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)

Example 1:less

MyCalendar();
MyCalendar.book(10, 20); // returns true
MyCalendar.book(15, 25); // returns false
MyCalendar.book(20, 30); // returns true
Explanation: 
The first event can be booked.  The second can't because time 15 is already booked by another event.
The third event can be booked, as the first event takes every time less than 20, but not including 20.

 

Note:函數

  • 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].

 

這道題讓咱們設計一個個人日曆類,裏面有一個book函數,須要給定一個起始時間和結束時間,與Google Calendar不一樣的是,咱們的事件事件上不能重疊,實際上這道題的本質就是檢查區間是否重疊。那麼咱們能夠暴力搜索,對於每個將要加入的區間,咱們都和已經已經存在的區間進行比較,看是否有重複。而新加入的區間和當前區間產生重複的狀況有兩種,一種是新加入區間的前半段重複,而且,另外一種是新加入區間的後半段重複。好比當前區間若是是[3, 8),那麼第一種狀況下新加入區間就是[6, 9),那麼觸發條件就是當前區間的起始時間小於等於新加入區間的起始時間,而且結束時間大於新加入區間的結束時間。第二種狀況下新加入區間就是[2,5),那麼觸發條件就是當前區間的起始時間大於等於新加入區間的起始時間,而且起始時間小於新加入區間的結束時間。這兩種狀況均返回false,不然就將新區間加入數組,並返回true便可,參見代碼以下:post

 

解法一:優化

class MyCalendar {
public:
    MyCalendar() {}
    
    bool book(int start, int end) {
        for (auto a : cal) {
            if (a.first <= start && a.second > start) return false;
            if (a.first >= start && a.first < end) return false;
        }
        cal.push_back({start, end});
        return true;
    }

private:
    vector<pair<int, int>> cal;
};

 

下面這種方法將上面方法的兩個if判斷融合成爲了一個,咱們來觀察兩個區間的起始和結束位置的關係發現,若是兩個區間的起始時間中的較大值小於結束區間的較小值,那麼就有重合,返回false。好比 [3, 8) 和 [6, 9),3和6中的較大值6,小於8和9中的較小值8,有重疊。再好比[3, 8) 和 [2, 5),3和2中的較大值3,就小於8和5中的較小值5,有重疊。而對於[3, 8) 和 [9, 10),3和9中的較大值9,不小於8和10中的較小值8,因此沒有重疊,參見代碼以下:this

 

解法二:url

class MyCalendar {
public:
    MyCalendar() {}
    
    bool book(int start, int end) {
        for (auto a : cal) {
            if (max(a.first, start) < min(a.second, end)) return false;
        }
        cal.push_back({start, end});
        return true;
    }

private:
    vector<pair<int, int>> cal;
};

 

上面兩種解法都是線性搜索,咱們起始能夠優化搜索時間,若是咱們的區間是有序的話。因此咱們用一個map來創建起始時間和結束時間的映射,map會按照起始時間進行自動排序。而後對於新進來的區間,咱們在已有區間中查找第一個不小於新入區間的起始時間的區間,若是這個區間存在的話,說明新入區間的起始時間小於等於當前區間,也就是解法一中的第二個if狀況,當前區間起始時間小於新入區間結束時間的話返回false。咱們還要跟前面一個區間進行查重疊操做,那麼判斷若是當前區間不是第一個區間的話,就找到前一個區間,此時是解法一中第一個if狀況,而且若是前一個區間的結束時間大於新入區間的起始時間的話,返回false。不然就創建新的映射,返回true便可,參見代碼以下:

 

解法三:

class MyCalendar {
public:
    MyCalendar() {}
    
    bool book(int start, int end) {
        auto it = cal.lower_bound(start);
        if (it != cal.end() && it->first < end) return false;
        if (it != cal.begin() && prev(it)->second > start) return false;
        cal[start] = end;
        return true;
    }

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

 

參考資料:

https://discuss.leetcode.com/topic/111205/java-8-liner-treemap

https://discuss.leetcode.com/topic/111244/simple-c-o-n-solution 

https://discuss.leetcode.com/topic/111306/clean-c-o-logn-solution

 

LeetCode All in One 題目講解彙總(持續更新中...)

相關文章
相關標籤/搜索