2402. Meeting Rooms III - Explanation
Description
There are n rooms numbered from 0 to n - 1. You are given a 2D integer array meetings where meetings[i] = [start[i], end[i]] means that a meeting will be held during the half-closed time interval [start[i], end[i]). All the values of start[i] are unique.
Meetings are allocated to rooms in the following manner:
Each meeting will take place in the unused room with the lowest number.
If there are no available rooms, the meeting will be delayed until a room becomes free. The delayed meeting should have the same duration as the original meeting.
When a room becomes unused, meetings that have an earlier original start time should be given the room.
Return the number of the room that held the most meetings. If there are multiple rooms, return the room with the lowest number.
A half-closed interval [a, b) is the interval between a and b including a and not including b.
Example 1:
Input: n = 2, meetings = [[1,10],[2,10],[3,10],[4,10]]
Output: 0Explanation:
- At time 1, the room with number 0 is available, the first meeting is allocated to it.
- At time 2, the room with number 1 is available, the second meeting is allocated to it.
- At time 10, the rooms with numbers 0 and 1 becomes unused, the third meeting is allocated to room number 0 and fourth meeting is allocated to room number 1.
The room with most meetings held and have lowest number is 0.
Example 2:
Input: n = 3, meetings = [[1,20],[2,10],[3,5],[6,8],[4,9]]
Output: 1Explanation:
- At time 1, all three rooms are not being used. The first meeting starts in room 0.
- At time 2, rooms 1 and 2 are not being used. The second meeting starts in room 1.
- At time 3, only room 2 is not being used. The third meeting starts in room 2.
- At time 4, all three rooms are being used. The fourth meeting is delayed.
- At time 5, the meeting in room 2 finishes. The fourth meeting starts in room 2 for the time period [5,10).
- At time 6, all three rooms are being used. The fifth meeting is delayed.
- At time 10, the meetings in rooms 1 and 2 finish. The fifth meeting starts in room 1 for the time period [10,12).
Room 0 held 1 meeting while rooms 1 and 2 each held 2 meetings, so we return 1 as it is lowest.
Constraints:
1 <= n <= 1001 <= meetings.length <= 100,000meetings[i].length == 20 <= start[i] < end[i] <= 500,000- All the values of
start[i]are unique.
Topics
Prerequisites
Before attempting this problem, you should be comfortable with:
- Sorting - Ordering meetings by start time to process them chronologically
- Heap / Priority Queue - Efficiently finding the minimum element (earliest available room or end time)
- Simulation - Tracking state changes over time as meetings are assigned and rooms become available
- Greedy Selection - Choosing the optimal room based on availability and room number constraints
1. Sorting + Brute Force
Intuition
Meetings must be processed in order of their start times. For each meeting, we check rooms in order from 0 to n - 1. If a room is free by the meeting's start time, we assign the meeting there. Otherwise, we find the room that becomes free earliest and delay the meeting until that room is available. We track how many meetings each room hosts and return the room with the most meetings, breaking ties by smallest room number.
Algorithm
- Sort meetings by start time.
- Initialize arrays
rooms(end times) andmeeting_count, both of sizen. - For each meeting
(start, end):- Scan rooms
0ton-1. Ifrooms[i]<=start, assign the meeting: setrooms[i]=end, incrementmeeting_count[i], and move to the next meeting. - While scanning, track
min_roomas the room with the earliest end time. - If no room is free, assign to
min_room: setrooms[min_room]+=(end - start)and incrementmeeting_count[min_room].
- Scan rooms
- Return the index with the maximum count (smallest index on ties).
class Solution:
def mostBooked(self, n: int, meetings: List[List[int]]) -> int:
meetings.sort()
rooms = [0] * n # end time of meetings in rooms
meeting_count = [0] * n
for s, e in meetings:
min_room = 0
found = False
for i in range(n):
if rooms[i] <= s:
found = True
meeting_count[i] += 1
rooms[i] = e
break
if rooms[min_room] > rooms[i]:
min_room = i
if found:
continue
meeting_count[min_room] += 1
rooms[min_room] += e - s
return meeting_count.index(max(meeting_count))Time & Space Complexity
- Time complexity:
- Space complexity:
Where is the number of rooms and is the number of meetings.
2. Two Min-Heaps
Intuition
Scanning all rooms for each meeting is slow. Instead, we use two min-heaps: one for available rooms (ordered by room number) and one for rooms in use (ordered by end time, then room number). When a meeting starts, we first move all rooms whose meetings have ended back to the available heap. If available is empty, we pop the earliest-ending room, delay the meeting, and push that room back to available. Then we pop the smallest available room, assign the meeting, and push it to the used heap.
Algorithm
- Sort meetings by start time.
- Initialize a min-heap
availablewith room numbers0ton-1. - Initialize an empty min-heap
usedstoring(end_time, room). - Initialize an array
countof sizen. - For each
(start, end):- While
usedis not empty andused[0].end_time<=start, pop fromusedand push the room toavailable. - If
availableis empty, pop(end_time, room)fromused, updateend=end_time+(end - start), and push room toavailable. - Pop
roomfromavailable, push(end, room)toused, and incrementcount[room].
- While
- Return the index with maximum count.
class Solution:
def mostBooked(self, n: int, meetings: List[List[int]]) -> int:
meetings.sort()
available = [i for i in range(n)] # Min heap for available rooms
used = [] # Min heap for used rooms [(end_time, room_number)]
count = [0] * n # Count of meetings for each room
for start, end in meetings:
while used and used[0][0] <= start:
_, room = heapq.heappop(used)
heapq.heappush(available, room)
if not available:
end_time, room = heapq.heappop(used)
end = end_time + (end - start)
heapq.heappush(available, room)
room = heapq.heappop(available)
heapq.heappush(used, (end, room))
count[room] += 1
return count.index(max(count))Time & Space Complexity
- Time complexity:
- Space complexity:
Where is the number of rooms and is the number of meetings.
3. One Min-Heap
Intuition
We can simplify to a single heap that tracks (end_time, room). Initially all rooms have end time 0. Before assigning a meeting, we update any rooms whose end time is before the meeting's start to have end time equal to the start (they become available). Then we pop the room with the smallest end time (and smallest room number on ties), assign the meeting, and push the room back with the new end time.
Algorithm
- Sort meetings by start time.
- Initialize a min-heap
availablewith(0, room)for each room0ton-1. - Initialize an array
countof sizen. - For each
(start, end):- While
available[0].end_time<start, pop(_, room)and push(start, room). - Pop
(end_time, room)from the heap. - Push
(end_time + (end - start), room)back to the heap. - Increment
count[room].
- While
- Return the index with maximum count.
class Solution:
def mostBooked(self, n: int, meetings: List[List[int]]) -> int:
meetings.sort()
available = []
count = [0] * n
for i in range(n):
heapq.heappush(available, (0, i))
for start, end in meetings:
while available and available[0][0] < start:
end_time, room = heapq.heappop(available)
heapq.heappush(available, (start, room))
end_time, room = heapq.heappop(available)
heapq.heappush(available, (end_time + (end - start), room))
count[room] += 1
return count.index(max(count))Time & Space Complexity
- Time complexity:
- time in average case.
- time in worst case.
- Space complexity:
Where is the number of rooms and is the number of meetings.
Common Pitfalls
Forgetting to Sort Meetings by Start Time
Meetings must be processed in chronological order. Without sorting, you cannot correctly determine which room becomes available first or when meetings need to be delayed.
Integer Overflow When Calculating Delayed End Times
When meetings are delayed, end times can grow very large. Using int instead of long can cause overflow. Always use long or equivalent 64-bit integer types for end times.
Incorrect Tie-Breaking for Room Selection
When multiple rooms are available, you must choose the room with the smallest index. When multiple rooms become free at the same time, you must also prefer the smaller index. Failing to implement this tie-breaking correctly leads to wrong answers.
Not Preserving Meeting Duration When Delaying
When a meeting is delayed because no room is available, the meeting duration must remain the same. The new end time should be earliest_available_time + (original_end - original_start), not simply the original end time.
Confusing Available vs Used Room Logic with Two Heaps
When using two heaps, it is easy to forget to move rooms from the used heap back to the available heap when their meetings end. Always check and transfer rooms whose end time is at or before the current meeting's start time before attempting to assign a room.
Sign in to join the discussion