Given an array of meeting time intervals intervals where intervals[i] = [starti, endi], return the minimum number of conference rooms required.
Input: intervals = [[0,30],[5,10],[15,20]]
Output: 2
Explanation:
- Meeting [0,30] uses Room 1
- Meeting [5,10] needs Room 2 (overlaps with [0,30])
- Meeting [15,20] can use Room 2 (starts after [5,10] ends)
Input: intervals = [[7,10],[2,4]]
Output: 1
Explanation: No overlaps, only 1 room needed
Input: intervals = [[1,5],[2,6],[3,7],[4,8]]
Output: 4
Explanation: All meetings overlap, need 4 separate rooms
1 <= intervals.length <= 10^40 <= starti < endi <= 10^6This is a classic interval scheduling problem that can be solved efficiently using a min-heap (priority queue).
Use a min-heap to track when conference rooms become available!
The heap stores end times of ongoing meetings. When a new meeting arrives:
The maximum heap size represents the minimum rooms needed.
We need to know which room becomes free earliest. A min-heap gives us the minimum end time in O(1) time.
heap.peek() <= meeting.start: A room is free! Remove from heap (reuse room)For intervals = [[0,30], [5,10], [15,20]]:
[30], Rooms: 130 > 5 (no room free)[10, 30], Rooms: 210 <= 15 (room is free!)[20, 30], Rooms: 2Result: 2 rooms minimum
Processing meetings in chronological order ensures we allocate rooms optimally. We always know all previous meetings have been considered.
Time Complexity: O(n log n)
Space Complexity: O(n)
import java.util.*;
class Solution {
public int minMeetingRooms(int[][] intervals) {
if (intervals == null || intervals.length == 0) {
return 0;
}
// Sort by start time
Arrays.sort(intervals, (a, b) -> a[0] - b[0]);
// Min-heap to track end times of meetings
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
// Add first meeting's end time
minHeap.add(intervals[0][1]);
// Process remaining meetings
for (int i = 1; i < intervals.length; i++) {
// If earliest ending meeting ends before current starts
// we can reuse that room
if (minHeap.peek() <= intervals[i][0]) {
minHeap.poll();
}
// Add current meeting's end time
minHeap.add(intervals[i][1]);
}
// Size of heap = number of rooms needed
return minHeap.size();
}
}
import heapq
def minMeetingRooms(intervals: List[List[int]]) -> int:
if not intervals:
return 0
# Sort by start time
intervals.sort(key=lambda x: x[0])
# Min-heap to track end times
min_heap = []
# Add first meeting's end time
heapq.heappush(min_heap, intervals[0][1])
# Process remaining meetings
for i in range(1, len(intervals)):
# If earliest ending meeting ends before current starts
if min_heap[0] <= intervals[i][0]:
heapq.heappop(min_heap)
# Add current meeting's end time
heapq.heappush(min_heap, intervals[i][1])
# Heap size = rooms needed
return len(min_heap)
Another elegant solution using start and end time arrays:
public int minMeetingRooms(int[][] intervals) {
int n = intervals.length;
int[] start = new int[n];
int[] end = new int[n];
// Separate start and end times
for (int i = 0; i < n; i++) {
start[i] = intervals[i][0];
end[i] = intervals[i][1];
}
// Sort both arrays
Arrays.sort(start);
Arrays.sort(end);
int rooms = 0;
int endPtr = 0;
// For each start time
for (int i = 0; i < n; i++) {
// If meeting starts after earliest end, reuse room
if (start[i] >= end[endPtr]) {
endPtr++;
} else {
// Need a new room
rooms++;
}
}
return rooms;
}
Time Complexity: O(n log n) Space Complexity: O(n)
This approach is elegant but the min-heap solution is more intuitive!
This problem demonstrates: