import heapq
class Solution:
def minMeetingRooms(self, intervals):
if not intervals:
return 0
intervals.sort(key=lambda x: x[0])
heap = []
heapq.heappush(heap, intervals[0][1])
for interval in intervals[1:]:
if interval[0] >= heap[0]:
heapq.heappop(heap)
heapq.heappush(heap, interval[1])
return len(heap)
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;
class Solution {
public:
int minMeetingRooms(vector<vector<int>>& intervals) {
if (intervals.empty()) return 0;
sort(intervals.begin(), intervals.end());
priority_queue<int, vector<int>, greater<int>> heap;
heap.push(intervals[0][1]);
for (int i = 1; i < intervals.size(); ++i) {
if (intervals[i][0] >= heap.top()) {
heap.pop();
}
heap.push(intervals[i][1]);
}
return heap.size();
}
};
import java.util.*;
class Solution {
public int minMeetingRooms(int[][] intervals) {
if (intervals.length == 0) return 0;
Arrays.sort(intervals, (a, b) -> a[0] - b[0]);
PriorityQueue<Integer> heap = new PriorityQueue<>();
heap.add(intervals[0][1]);
for (int i = 1; i < intervals.length; i++) {
if (intervals[i][0] >= heap.peek()) {
heap.poll();
}
heap.add(intervals[i][1]);
}
return heap.size();
}
}
var minMeetingRooms = function(intervals) {
if (intervals.length === 0) return 0;
intervals.sort((a, b) => a[0] - b[0]);
let heap = [];
const addRoom = (end) => {
heap.push(end);
heap.sort((a, b) => a - b);
};
addRoom(intervals[0][1]);
for (let i = 1; i < intervals.length; i++) {
if (intervals[i][0] >= heap[0]) {
heap.shift();
}
addRoom(intervals[i][1]);
}
return heap.length;
};
You are given an array of meeting time intervals, where each interval is represented as a pair [start, end]
. Your task is to determine the minimum number of conference rooms required so that all meetings can take place without any overlaps.
Example: If the input is [[0, 30], [5, 10], [15, 20]]
, you should return 2
because at most two meetings overlap at any point in time.
The first instinct might be to check each meeting against every other meeting to see if they overlap, assigning rooms as needed. While this works for small inputs, it quickly becomes inefficient (brute-force).
To optimize, we can shift perspective: instead of focusing on assigning rooms directly, let's track when rooms become free. If a meeting starts after another ends, it can reuse the same room. Thus, we need a way to efficiently keep track of the earliest ending meetings.
This leads us to use a min-heap (priority queue) to always know which room will be free next. By sorting meetings by start time and always checking the soonest available room, we ensure we use the minimum number of rooms.
Using a heap lets us efficiently find and release rooms as soon as they become available, ensuring we never use more rooms than necessary.
Let's use the input [[0, 30], [5, 10], [15, 20]]
:
[[0, 30], [5, 10], [15, 20]]
[30]
[10, 30]
[20, 30]
This demonstrates how the heap always tracks the rooms currently in use and allows us to reuse rooms optimally.
O(n^2)
time and O(n)
space.
O(n \log n)
O(n \log n)
O(n \log n)
n
end times, so O(n)
space.
The heap-based solution is much more efficient, especially for large inputs.
The key insight is to treat the problem as one of efficiently tracking room availability, not just overlaps. By sorting meetings and using a min-heap to always know which room becomes free next, we can assign rooms optimally. This approach is both elegant and efficient, leveraging simple data structures to solve a classic scheduling problem.