[
bst
heap
intervals
]
Leetcode 0855 Exam Room
Problem statement
https://leetcode.com/problems/exam-room/
Solution
There is straightforward solution with O(n) complexity to seat and leave, we just keep sorted list and find shortest distance. However we can do better: let us have:
self.placesare occupied places, we keep them in SortedList python objectself.scoresare segments between two adjacent persons with scores: imagine, that we have people on places[-1, 4, 9, 12], wheren = 12(we use two dummy seats:-1andn). Then we have3possible segments where we can seat people:[-1, 4]and score here is4, because putting person on seat0it will be4seats away from any other one. Next segment is[4, 9]and we have score2here, if we put new person on seat6. Finally, for segment[9, 12]score is 2, because we can put person on seat number11. In the beginning we create one segment[-1, n]and its score.priorityfunction will evaluate score of segment, here we need to deal with two cases: when we are in the middle or not.seatfunction will work like this: first, we found the biggest element fromself.scores, it will be the segment we need to seat person to. Then, if left end of this segment is-1, we need to seat person on place0, if right end isn, we need to seat person on placen - 1, in other case we seat him in the middle. We also add two new segments toself.scores, one place toself.placesand returnmid.leaveLet us find index of person we need to delete, find its neighbours, delete one segment and add two new segments from toself.scoresand remove place fromself.places.
Complexity
Time complexity of both operations is O(log n), where n is current number of occupied seats.
Code
from sortedcontainers import SortedList
class ExamRoom:
def __init__(self, N):
self.N = N
self.places = SortedList([-1, N])
self.scores = SortedList()
self.priority(-1,N,SortedList.add)
def priority(self, beg, end, func):
if beg == -1 or end == self.N:
score = beg - end + 1
else:
score = -((end - beg) // 2)
func(self.scores, (score, beg, end))
def seat(self):
_, beg, end = self.scores.pop(0)
if beg == -1:
mid = beg + 1
elif end == self.N:
mid = end - 1
else:
mid = (beg + end) // 2
self.priority(beg, mid, SortedList.add)
self.priority(mid, end, SortedList.add)
self.places.add(mid)
return mid
def leave(self, p):
ind = self.places.index(p)
beg, end = self.places[ind-1], self.places[ind+1]
self.priority(beg, end, SortedList.add)
self.priority(beg, p, SortedList.remove)
self.priority(p, end, SortedList.remove)
self.places.remove(p)
Remark
There is alternative solution with the same complexity, using heaps with lazy updates. We need to keep tuples of four elements: last one is flag if this segment deleted or not. Also we need to keep dictionary (or two dictionaries), which connects each point to left and right segments.