leetcode 732. 我的日程安排表 解法

 

題目如下:

實現一個 MyCalendar 類來存放你的日程安排,你可以一直添加新的日程安排。

MyCalendar 有一個 book(int start, int end)方法。它意味着在start到end時間內增加一個日程安排,注意,這裏的時間是半開區間,即 [start, end), 實數 x 的範圍爲,  start <= x < end

當 K 個日程安排有一些時間上的交叉時(例如K個日程安排都在同一時間內),就會產生 K 次預訂。

每次調用 MyCalendar.book方法時,返回一個整數 K ,表示最大的 K 次預訂。

請按照以下步驟調用MyCalendar 類: MyCalendar cal = new MyCalendar();MyCalendar.book(start, end)

示例 1:

MyCalendarThree();
MyCalendarThree.book(10, 20); // returns 1
MyCalendarThree.book(50, 60); // returns 1
MyCalendarThree.book(10, 40); // returns 2
MyCalendarThree.book(5, 15); // returns 3
MyCalendarThree.book(5, 10); // returns 3
MyCalendarThree.book(25, 55); // returns 3
解釋: 
前兩個日程安排可以預訂並且不相交,所以最大的K次預訂是1。
第三個日程安排[10,40]與第一個日程安排相交,最高的K次預訂爲2。
其餘的日程安排的最高K次預訂僅爲3。
請注意,最後一次日程安排可能會導致局部最高K次預訂爲2,但答案仍然是3,原因是從開始到最後,時間[10,20],[10,40]和[5,15]仍然會導致3次預訂。

說明:

  • 每個測試用例,調用 MyCalendar.book 函數最多不超過 400次。
  • 調用函數 MyCalendar.book(start, end)時, start 和 end 的取值範圍爲 [0, 10^9]

分析:

此題的關鍵是返回的K值應該是隨着時間順序到目前爲止日程交叉數最大的數,所以可以把對時間範圍的關注轉移到對初始點的K值數的計算上。即,每增加一個日程後對涉及到的開始點的最大K值得影響並對涉及的點做增一操作,最後返回這些K值中的最大值。

此題的另外一種解法是線段樹的惰性傳播(Lazy Propagation in Segment Tree)

參考代碼如下:

class MyCalendarThree(object):

    def __init__(self):
        self.seg = collections.defaultdict(int)
        self.lazy = collections.defaultdict(int)
        
    def book(self, start, end):
        def update(s, e, l = 0, r = 10**9, ID = 1):
            if r <= s or e <= l: return 
            if s <= l < r <= e:
                self.seg[ID] += 1
                self.lazy[ID] += 1
            else:
                m = (l + r) // 2
                update(s, e, l, m, 2 * ID)
                update(s, e, m, r, 2*ID+1)
                self.seg[ID] = self.lazy[ID] + max(self.seg[2*ID], self.seg[2*ID+1])
        update(start, end)
        return self.seg[1] + self.lazy[1]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章