You are implementing a program to use as your calendar. We can add a new event if adding the event will not cause a triple booking.
A triple booking happens when three events have some non-empty intersection (i.e., some moment is common to all the three events.).
The event can be represented as a pair of integers startTime
and endTime
that represents a booking on the half-open interval [startTime, endTime)
, the range of real numbers x
such that startTime <= x < endTime
.
Implement the MyCalendarTwo
class:
MyCalendarTwo()
Initializes the calendar object.boolean book(int startTime, int endTime)
Returns true
if the event can be added to the calendar successfully without causing a triple booking. Otherwise, return false
and do not add the event to the calendar.Example:
Let's walk through an example using the following sequence of calls:
MyCalendarTwo myCalendarTwo = new MyCalendarTwo();
myCalendarTwo.book(10, 20); // return True
myCalendarTwo.book(50, 60); // return True
myCalendarTwo.book(10, 40); // return True
myCalendarTwo.book(5, 15); // return False
myCalendarTwo.book(5, 10); // return True
myCalendarTwo.book(25, 55); // return True
Can you implement the MyCalendarTwo
class and the book
method to handle these bookings and avoid triple bookings?
A brute force approach would involve storing all the bookings as intervals and, for each new booking, checking for triple bookings by iterating through all possible combinations of three intervals (including the new one) and checking if they overlap. This is inefficient but conceptually simple.
(start, end)
tuples.book(start, end)
is called:
n
bookings in the list, this will take O(n^3) time.max(start1, start2, start3) < min(end1, end2, end3)
. If they intersect, return false
and remove the newly added booking.true
.class MyCalendarTwo:
def __init__(self):
self.bookings = []
def book(self, start: int, end: int) -> bool:
self.bookings.append((start, end))
n = len(self.bookings)
for i in range(n):
for j in range(i + 1, n):
for k in range(j + 1, n):
s1, e1 = self.bookings[i]
s2, e2 = self.bookings[j]
s3, e3 = self.bookings[k]
if max(s1, s2, s3) < min(e1, e2, e3):
self.bookings.pop()
return False
return True
O(n^3) for each call to book
, where n
is the number of bookings.
O(n), where n
is the number of bookings, to store the list of intervals.
A more efficient approach involves tracking the number of overlaps at any given time using two lists: one for single bookings and one for double bookings.
single_bookings
and double_bookings
.book(start, end)
is called:
double_bookings
. If the new interval intersects with any interval in double_bookings
, it means there will be a triple booking. In that case, return false
.single_bookings
. If there is an intersection, add the intersection interval to double_bookings
.single_bookings
.class MyCalendarTwo:
def __init__(self):
self.single_bookings = []
self.double_bookings = []
def book(self, start: int, end: int) -> bool:
for s, e in self.double_bookings:
if start < e and end > s:
return False
for s, e in self.single_bookings:
intersection_start = max(start, s)
intersection_end = min(end, e)
if intersection_start < intersection_end:
self.double_bookings.append((intersection_start, intersection_end))
self.single_bookings.append((start, end))
return True
O(n) for each call to book
, where n
is the number of existing bookings, due to iterating through single_bookings
and double_bookings
.
O(n), where n
is the number of bookings, to store single_bookings
and double_bookings
.
[10, 20]
and [20, 30]
) should be allowed as they do not overlap.