Meeting Rooms III
You are given an integer n. 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.
Most Booked Meeting Room
Problem Statement
You are given a number n. There are n rooms, numbered from 0 to n - 1.
You are also given a 2D array called meetings. Each entry, meetings[i] = [start_i, end_i], tells us that a meeting happens during the time period [start_i, end_i). This means the meeting includes the start time but does not include the end time. All the start times are different from each other.
Meetings are given to rooms using these rules:
- Each meeting goes into the free room with the lowest number.
- If no room is free, the meeting is delayed until a room opens up. The delayed meeting keeps the same duration as before.
- When a room becomes free, meetings with an earlier original start time get priority for that room.
Return the number of the room that held the most meetings. If more than one room is tied for the most, return the room with the lowest number.
A half-closed interval
[a, b)means the range fromatob, includingabut not includingb.
Examples
Example 1
Input: n = 2, meetings = [[0,10],[1,5],[2,7],[3,4]]
Output: 0
Explanation:
- At time 0, both rooms are free. The first meeting starts in room 0.
- At time 1, only room 1 is free. The second meeting starts in room 1.
- At time 2, both rooms are busy. The third meeting is delayed.
- At time 3, both rooms are busy. The fourth meeting is delayed.
- At time 5, the meeting in room 1 finishes. The third meeting starts in room 1, running from
[5,10). - At time 10, both meetings finish. The fourth meeting starts in room 0, running from
[10,11).
Rooms 0 and 1 both held 2 meetings. Since they are tied, we return the lower number, 0.
Example 2
Input: n = 3, meetings = [[1,20],[2,10],[3,5],[4,9],[6,8]]
Output: 1
Explanation:
- At time 1, all three rooms are free. The first meeting starts in room 0.
- At time 2, rooms 1 and 2 are free. The second meeting starts in room 1.
- At time 3, only room 2 is free. The third meeting starts in room 2.
- At time 4, all rooms are busy. The fourth meeting is delayed.
- At time 5, the meeting in room 2 finishes. The fourth meeting starts in room 2, running from
[5,10). - At time 6, all rooms are busy. The fifth meeting is delayed.
- At time 10, the meetings in rooms 1 and 2 finish. The fifth meeting starts in room 1, running from
[10,12).
Room 0 held 1 meeting. Rooms 1 and 2 each held 2 meetings. So we return 1.
Constraints
1 ≤ n ≤ 1001 ≤ meetings.length ≤ 10⁵meetings[i].length == 20 ≤ start_i < end_i ≤ 5 × 10⁵- All start times are different from each other.
Naive Solution
The steps for this simple approach:
- We create an array called
rooms. This stores the end time of the current meeting in each room. - We create another array called
meetingCount. This tracks how many meetings each room has held. - We sort all the meetings by their start time.
- For each meeting, we check every room. If a room's current end time is less than or equal to the meeting's start time, that room is free. We assign the meeting there, update its end time, and increase its meeting count.
- If no room is free, we find the room that will free up soonest (the one with the lowest end time). We delay the meeting there. Its new end time becomes:
previous end time + (meeting duration). - At the end, we look through
meetingCountand find the room with the highest count. If there's a tie, the lowest room number wins automatically, since we scan from left to right.
Naive Code
var mostBooked = function (n, meetings) {
//create array for rooms which will store end time of meetings
// create a array for count of each meeting
// sort meetings array with arrival time
// for each meetings check available room end time >= meetings start time
// if yes update end time, count of room and break
// if no rooms are found update end time of meeting with lowest end time with end-start
// find max count of room array
var rooms = new Array(n).fill(0);
var meetingCount = new Array(n).fill(0);
var sortedMeetings = meetings.sort((a, b) => a[0] - b[0]);
for (const meet of sortedMeetings) {
let lowestIdx = 0;
var roomUpdated = false
for (let i = 0; i < rooms.length; i++) {
if (rooms[i] < rooms[lowestIdx]) {
lowestIdx = i;
}
if (meet[0] >= rooms[i]) {
rooms[i] = meet[1]; // update the room's end time
meetingCount[i] = meetingCount[i] + 1;
roomUpdated = true;
break;
}
}
if (!roomUpdated) {
rooms[lowestIdx] = rooms[lowestIdx] + meet[1] - meet[0];
meetingCount[lowestIdx] = meetingCount[lowestIdx] + 1;
}
}
let maxMeetingCount = -Infinity;
let maxIndex = 0;
for (let i = 0; i < meetingCount.length; i++) {
if (meetingCount[i] > maxMeetingCount) {
maxMeetingCount = meetingCount[i];
maxIndex = i;
}
}
return maxIndex;
};
This works, but it checks every room for every meeting. This can get slow when there are many rooms and many meetings.
Optimized Solution
To make this faster, we use two heaps instead of scanning every room each time:
- A min heap called
availableRooms. This stores the numbers of free rooms, so we can always grab the lowest-numbered free room quickly. - A min heap called
busyRooms. This stores[endTime, roomNumber]pairs, so we can always find the room that will free up soonest.
Here is how it works:
- We start by putting all room numbers into
availableRooms, since every room is free at the beginning. - We sort the meetings by start time.
- For each meeting:
- First, we check
busyRooms. Any room whose meeting has already ended by this meeting's start time gets moved back intoavailableRooms. - If
availableRoomsis not empty, we take the lowest-numbered free room. We assign the meeting there, increase its meeting count, and push its new end time intobusyRooms. - If
availableRoomsis empty, no room is free. We take the room frombusyRoomsthat frees up soonest. We delay the meeting there. Its new end time becomes:(the room's free time) + (meeting duration).
- First, we check
- At the end, we scan
meetingCountto find the room with the highest count, just like before.
This avoids checking every single room for every meeting, which makes it much faster for large inputs.
Optimized Code
class MinHeap {
constructor(comparator) {
this.heap = [];
this.comparator = comparator;
}
size() { return this.heap.length; }
isEmpty() { return this.heap.length === 0; }
peek() { return this.heap[0]; }
push(val) {
this.heap.push(val);
this._bubbleUp(this.heap.length - 1);
}
pop() {
const top = this.heap[0];
const last = this.heap.pop();
if (this.heap.length > 0) {
this.heap[0] = last;
this._bubbleDown(0);
}
return top;
}
_bubbleUp(i) {
while (i > 0) {
const parent = (i - 1) >> 1;
if (this.comparator(this.heap[parent], this.heap[i]) <= 0) break;
[this.heap[parent], this.heap[i]] = [this.heap[i], this.heap[parent]];
i = parent;
}
}
_bubbleDown(i) {
const n = this.heap.length;
while (true) {
const left = 2 * i + 1, right = 2 * i + 2;
let smallest = i;
if (left < n && this.comparator(this.heap[left], this.heap[smallest]) < 0) smallest = left;
if (right < n && this.comparator(this.heap[right], this.heap[smallest]) < 0) smallest = right;
if (smallest === i) break;
[this.heap[i], this.heap[smallest]] = [this.heap[smallest], this.heap[i]];
i = smallest;
}
}
}
var mostBooked = function (n, meetings) {
const meetingCount = new Array(n).fill(0);
const sortedMeetings = [...meetings].sort((a, b) => a[0] - b[0]);
const availableRooms = new MinHeap((a, b) => a - b); // just room numbers
const busyRooms = new MinHeap((a, b) => a[0] - b[0]); // [endTime, roomNumber]
for (let i = 0; i < n; i++) {
availableRooms.push(i);
}
for (const [start, end] of sortedMeetings) {
// Free every room whose meeting has ended by this meeting's start time
while (!busyRooms.isEmpty() && busyRooms.peek()[0] <= start) {
const [, roomNumber] = busyRooms.pop();
availableRooms.push(roomNumber);
}
if (!availableRooms.isEmpty()) {
// A room is free right now — take the lowest-numbered one
const room = availableRooms.pop();
meetingCount[room]++;
busyRooms.push([end, room]);
} else {
// No room free — delay until the soonest-freeing room opens up
const [freeTime, room] = busyRooms.pop();
const duration = end - start;
meetingCount[room]++;
busyRooms.push([freeTime + duration, room]);
}
}
let maxCount = -Infinity;
let maxIndex = 0;
for (let i = 0; i < meetingCount.length; i++) {
if (meetingCount[i] > maxCount) {
maxCount = meetingCount[i];
maxIndex = i;
}
}
return maxIndex;
};