segment tree
intervals
accumulate
sweep line
]
Leetcode 0732 My Calendar III
Problem statement
https://leetcode.com/problems/my-calendar-iii/
Solution 1
The idea is to use idea of cumulative sum: instead of booking [a, b]
segment, we add 1
to points[a]
and remove 1
from points[b]
(see this trick in 0253 Meeting Rooms II problem).
Complexity
Time complexity of this approach is O(n^2*log n)
, because we need to sort data n
times.
Code
class MyCalendarThree:
def __init__(self):
self.points = Counter()
def book(self, start, end):
self.points[start] += 1
self.points[end] -= 1
return max(accumulate(i for _, i in sorted(self.points.items())))
Solution 2
There is also segment tree solution with O(n log N)
solution, where N
is the biggest value of numbers in intervals. The idea is to use sparse segment tree with lazy updates (see Segment tree pattern). After we use it code is pretty easy: we just need to update segment and then return query for each new point.
Complexity
It is O(n log N)
for time and space.
Code
class SegmentTree:
def __init__(self, N, update_fn, query_fn):
self.UF, self.QF = update_fn, query_fn
self.T = defaultdict(int) # [0] * (4*N)
self.L = defaultdict(int) # [0] * (4*N)
def push(self, v):
for u in [2*v, 2*v+1]:
self.T[u] = self.UF(self.T[u], self.L[v])
self.L[u] = self.UF(self.L[u], self.L[v])
self.L[v] = 0
def update(self, v, tl, tr, l, r, h):
if l > r: return
if l == tl and r == tr:
self.T[v] = self.UF(self.T[v], h)
self.L[v] = self.UF(self.L[v], h)
else:
self.push(v)
tm = (tl + tr)//2
self.update(v*2, tl, tm, l, min(r, tm), h)
self.update(v*2+1, tm+1, tr, max(l, tm+1), r, h)
self.T[v] = self.QF(self.T[v*2], self.T[v*2+1])
def query(self, v, tl, tr, l, r):
if l > r: return -float("inf")
if l <= tl and tr <= r: return self.T[v]
self.push(v)
tm = (tl + tr)//2
return self.QF(self.query(v*2, tl, tm, l, min(r, tm)), self.query(v*2+1, tm+1, tr, max(l, tm+1), r))
class MyCalendarThree:
def __init__(self):
self.N = N = 10**9 + 1
self.STree = SegmentTree(N, lambda a,b: a+b, max)
def book(self, start, end):
self.STree.update(1, 0, self.N-1, start + 1, end, 1)
return self.STree.query(1, 0, self.N-1, 1, 10**9)
Solution 3
There is also O(n^2)
solution, similar to the first solution, where we do not sort our data each time, but keep it sorted and insert elements in O(n)
. Note, that this solution can be optimized, we do not need to iterate over all lst
, but we can find places i
and j
where we insert our new segment and then look only on [i, j]
interval. Complexity will be the same, but in practice it will work like 5
times faster.
Complexity
It is O(n^2)
for time and O(n)
for space.
Code
class MyCalendarThree:
def __init__(self):
self.lst = []
def book(self, start, end):
bisect.insort(self.lst, (start, 1))
bisect.insort(self.lst, (end, -1))
k, tmp = 0, 0
for t, n in self.lst:
tmp += n
k = max(k, tmp)
return k
Remark
Open question, if there is O(n log n)
solution.