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 seats of size n, where false means 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).
classSeatManager:def__init__(self, n:int):
self.seats =[False]* n
defreserve(self)->int:for i inrange(len(self.seats)):ifnot self.seats[i]:
self.seats[i]=Truereturn i +1defunreserve(self, seatNumber:int)->None:
self.seats[seatNumber -1]=False
publicclassSeatManager{privateboolean[] seats;publicSeatManager(int n){
seats =newboolean[n];}publicintreserve(){for(int i =0; i < seats.length; i++){if(!seats[i]){
seats[i]=true;return i +1;}}return-1;}publicvoidunreserve(int seatNumber){
seats[seatNumber -1]=false;}}
classSeatManager{private:
vector<bool> seats;public:SeatManager(int n):seats(n,false){}intreserve(){for(int i =0; i < seats.size(); i++){if(!seats[i]){
seats[i]=true;return i +1;}}return-1;}voidunreserve(int seatNumber){
seats[seatNumber -1]=false;}};
classSeatManager{/**
* @param {number} n
*/constructor(n){this.seats =newArray(n).fill(false);}/**
* @return {number}
*/reserve(){for(let i =0; i <this.seats.length; i++){if(!this.seats[i]){this.seats[i]=true;return i +1;}}}/**
* @param {number} seatNumber
* @return {void}
*/unreserve(seatNumber){this.seats[seatNumber -1]=false;}}
publicclassSeatManager{privatebool[] seats;publicSeatManager(int n){
seats =newbool[n];}publicintReserve(){for(int i =0; i < seats.Length; i++){if(!seats[i]){
seats[i]=true;return i +1;}}return-1;}publicvoidUnreserve(int seatNumber){
seats[seatNumber -1]=false;}}
type SeatManager struct{
seats []bool}funcConstructor(n int) SeatManager {return SeatManager{seats:make([]bool, n)}}func(this *SeatManager)Reserve()int{for i :=0; i <len(this.seats); i++{if!this.seats[i]{
this.seats[i]=truereturn i +1}}return-1}func(this *SeatManager)Unreserve(seatNumber int){
this.seats[seatNumber-1]=false}
classSeatManager(n: Int){privateval seats =BooleanArray(n)funreserve(): Int {for(i in seats.indices){if(!seats[i]){
seats[i]=truereturn i +1}}return-1}fununreserve(seatNumber: Int){
seats[seatNumber -1]=false}}
classSeatManager{privatevar seats:[Bool]init(_ n:Int){
seats =[Bool](repeating:false, count: n)}funcreserve()->Int{for i in0..<seats.count {if!seats[i]{
seats[i]=truereturn i +1}}return-1}funcunreserve(_ seatNumber:Int){
seats[seatNumber -1]=false}}
Time & Space Complexity
Time complexity:
O(n) time for initialization.
O(n) time for each reserve() function call.
O(1) time for each unreserve() function call.
Space complexity: O(n)
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.
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.
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 available and set nextSeat = 1.
For reserve():
If the set is not empty, remove and return the smallest element.
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.