題目如下:
實現一個 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]