1845. Seat Reservation Manager - Explanation
Description
Implement SeatManager to manage seats numbered from 1 through n.
SeatManager(n)creates a manager with all seats available.reserve()reserves the available seat with the smallest number and returns that number.unreserve(seatNumber)makes a reserved seat available again.
Every call to reserve has at least one available seat. Every call to unreserve refers to a seat that is currently reserved.
Example 1:
Input: ["SeatManager","reserve","reserve","unreserve","reserve"]
[[3],[],[],[1],[]]
Output: [null,1,2,null,1]Explanation: The first two calls reserve seats 1 and 2. Releasing seat 1 makes it the smallest available seat again, so the final reserve returns 1.
Example 2:
Input: ["SeatManager","reserve","unreserve","reserve"]
[[1],[],[1],[]]
Output: [null,1,null,1]Explanation: There is only one seat. After reserving and releasing it, the next reserve returns seat 1 again.
Example 3:
Input: ["SeatManager","reserve","reserve","reserve","unreserve","unreserve","reserve","reserve"]
[[4],[],[],[],[3],[1],[],[]]
Output: [null,1,2,3,null,null,1,3]Explanation: The first three reservations return 1, 2, and 3. Seats 3 and 1 are then released. The next two reservations return 1 and 3 in that order, ahead of the never-reserved seat 4.
Constraints:
1 <= n <= 1000001 <= seatNumber <= n- At most
100000calls are made toreserveandunreservecombined. - A seat is available whenever
reserveis called. - A seat is reserved whenever
unreserveis called for it.
Topics
Prerequisites
Before attempting this problem, you should be comfortable with:
- Arrays - Using boolean arrays to track state and linear scanning for finding elements
- Heap / Priority Queue - Understanding min-heap operations for efficient retrieval of the smallest element
- Ordered Set - Using balanced binary search trees (TreeSet, SortedSet) for maintaining sorted elements with efficient min retrieval
1. Brute Force
Intuition
The simplest way to manage seat reservations is to track each seat's status with a boolean array. When someone reserves, we scan from the beginning to find the first unreserved seat. When someone unreserves, we simply mark that seat as available again. This guarantees we always return the smallest available seat number, but the linear scan makes reservations slow for large numbers of seats.
Algorithm
- Initialize a boolean array
seatsof sizen, wherefalsemeans unreserved. - For
reserve():- Scan through the array from index
0. - Find the first seat that is
false(unreserved). - Mark it as
true(reserved) and return the seat number (index + 1).
- Scan through the array from index
- For
unreserve(seatNumber):- Mark
seats[seatNumber - 1]asfalse.
- Mark
class SeatManager:
def __init__(self, n: int):
self.seats = [False] * n
def reserve(self) -> int:
for i in range(len(self.seats)):
if not self.seats[i]:
self.seats[i] = True
return i + 1
def unreserve(self, seatNumber: int) -> None:
self.seats[seatNumber - 1] = FalseTime & Space Complexity
- Time complexity:
- time for initialization.
- time for each function call.
- time for each function call.
- Space complexity:
2. Min-Heap
Intuition
To efficiently retrieve the smallest available seat, we can use a min-heap. By initializing the heap with all seat numbers from 1 to n, the smallest seat is always at the top. Reserving pops from the heap, and unreserving pushes back onto it. The heap maintains the ordering automatically.
Algorithm
- Initialize a min-heap with all seat numbers from 1 to
n. - For
reserve():- Pop and return the minimum element from the heap.
- For
unreserve(seatNumber):- Push
seatNumberback into the heap.
- Push
Time & Space Complexity
- Time complexity:
- time for initialization.
- time for each function call.
- time for each function call.
- Space complexity:
3. Min-Heap (Optimal)
Intuition
Rather than pre-populating the heap with all n seats, we can lazily assign seats. We track a counter nextSeat that represents the next fresh seat to assign. When reserving, if no previously unreserved seats are in the heap, we simply hand out nextSeat and increment it. This avoids O(n log n) initialization and handles the common case where seats are reserved in order very efficiently.
Algorithm
- Initialize an empty min-heap and set
nextSeat = 1. - For
reserve():- If the heap is not empty, pop and return the minimum.
- Otherwise, return
nextSeatand increment it.
- For
unreserve(seatNumber):- Push
seatNumberinto the heap.
- Push
class SeatManager:
def __init__(self, n: int):
self.minHeap = []
self.nextSeat = 1
def reserve(self) -> int:
if self.minHeap:
return heapq.heappop(self.minHeap)
seat = self.nextSeat
self.nextSeat += 1
return seat
def unreserve(self, seatNumber: int) -> None:
heapq.heappush(self.minHeap, seatNumber)Time & Space Complexity
- Time complexity:
- time for initialization.
- time for each function call.
- time for each function call.
- Space complexity:
4. Ordered Set
Intuition
An ordered set (like TreeSet or SortedSet) keeps elements sorted and allows efficient retrieval of the minimum. Similar to the optimal min-heap approach, we lazily track unreserved seats. The ordered set provides O(log n) insertion, deletion, and minimum retrieval, making it a clean alternative to the heap.
Algorithm
- Initialize an empty ordered set
availableand setnextSeat = 1. - For
reserve():- If the set is not empty, remove and return the smallest element.
- Otherwise, return
nextSeatand increment it.
- For
unreserve(seatNumber):- Add
seatNumberto the set.
- Add
class SeatManager:
def __init__(self, n: int):
self.available = SortedSet()
self.nextSeat = 1
def reserve(self) -> int:
if self.available:
return self.available.pop(0)
seat = self.nextSeat
self.nextSeat += 1
return seat
def unreserve(self, seatNumber: int) -> None:
self.available.add(seatNumber)Time & Space Complexity
- Time complexity:
- time for initialization.
- time for each function call.
- time for each function call.
- Space complexity:
Common Pitfalls
Pre-populating All Seats in the Heap
A common inefficiency is initializing the min-heap with all n seats upfront. This results in O(n log n) initialization time and O(n) space even when only a few reservations are made. The optimal approach uses lazy initialization: track a nextSeat counter and only add seats to the heap when they are unreserved.
Off-by-One Errors with 1-Based Seat Numbers
Seat numbers in this problem are 1-indexed, but arrays are 0-indexed. A frequent mistake is confusing these indexing schemes, leading to returning seat 0 (invalid) or accessing seats[seatNumber] instead of seats[seatNumber - 1] when using a boolean array approach.
Using a Max-Heap Instead of a Min-Heap
When implementing the heap-based solution, accidentally using a max-heap instead of a min-heap will return the largest available seat number instead of the smallest. Ensure you configure the heap correctly for minimum extraction, which may require using a custom comparator or negating values depending on your language.
Sign in to join the discussion