[
array
bst
intervals
segment tree
]
Leetcode 0731 My Calendar II
Problem statement
https://leetcode.com/problems/my-calendar-ii/
Solution 1
There is O(n^2)
solution with the following idea: let self.one
be sorted list with intervals, which are visited once and self.two
intervals visited twice. Then when we have new interval, we:
- Check if this interval have intersections with
self.two
list. If it has, we immediately returnFalse
. - Next, we find place, where our interval is intersecting with
self.one
list. First of all, this interval is not intersecting withself.two
, in opposite case we already should have returned False. So, we just need to insert in right place part ofself.one
list. Note also, that depending on parity of start and end, we either add it or not (see Problem 0715 Range Module for similar trick). - Also, we need to fix
self.one
: remove all elements, which are now covered twice and again use trick with ends. \end{itemize}
Complexity
Overall time complexity is O(n^2)
, space complexity is O(n)
.
Code
class MyCalendarTwo:
def __init__(self):
self.one = [] # intervals that are booked once
self.two = [] # intervals that are booked twice
def book(self, start, end):
if (t := bisect.bisect_right(self.two, start)) % 2: return False
if t != bisect.bisect_left(self.two, end): return False
i = bisect.bisect_right(self.one, start)
j = bisect.bisect_left(self.one, end)
self.two[t:t] = [start]*(i%2) + self.one[i:j] + [end]*(j%2)
self.one[i:j] = [start]*((i+1)%2) + [end]*((j+1)%2)
return True
Solution 2
There is also O(n log n)
algorithm (which in practice works more or less the same): we use Sorted Lists instead of usual lists: then each element will be added and removed from each sorted list O(1)
times (to check)
Complexity
It is O(n log n)
for time and O(n)
for space.
Code
from sortedcontainers import SortedList
class MyCalendarTwo:
def __init__(self):
self.one = SortedList() # intervals that are booked once
self.two = SortedList() # intervals that are booked twice
def book(self, start, end):
if (t := SortedList.bisect_right(self.two, start)) % 2: return False
if t != SortedList.bisect_left(self.two, end): return False
i = SortedList.bisect_right(self.one, start)
j = SortedList.bisect_left(self.one, end)
for item in [start]*(i%2) + self.one[i:j] + [end]*(j%2): self.two.add(item)
for _ in range(j-i): del self.one[i]
for item in [start]*((i+1)%2) + [end]*((j+1)%2): self.one.add(item)
return True
Remark
Notice that there is also segment tree solution, where we use sparse segment tree with complexity O(n log M)
, where M = 10**9
.