The LeetCode problem “Meeting Rooms II” requires us to determine the minimum number of meeting rooms needed to accommodate a set of meetings with a given start and end times. For example, if we have meetings scheduled from (0, 30), (5, 10), and (15, 20), we need two meeting rooms because the first meeting overlaps with the other two.
Algorithm and Data Structure Choice
Chosen Algorithm: Greedy Algorithm with a priority queue.
The algorithm follows a greedy strategy, and the priority queue (min-heap) efficiently manages the end times of meetings to keep track of overlapping meetings.
1. Interval Overlap Problem: The problem involves managing intervals (start and end times), which often requires sorting or a heap to track the next available resource (in this case, the next available meeting room).
2. Minimization Problem: We need to minimize the number of resources (meeting rooms), suggesting a greedy approach where we always make the optimal choice at each step (assigning rooms based on availability).
3. Dynamic Nature of Meetings: Meetings can start and end at different times, requiring a data structure that allows quick access to the current state of resources (like meeting rooms).
The greedy algorithm with a priority queue was chosen because it effectively balances the need for efficiency and accuracy:
• The priority queue allows us to always access the meeting room that will be free the soonest, ensuring optimal resource allocation.
• Sorting the meetings ensures that we process them in the correct order, which is crucial for determining overlaps.
High-Level Algorithm Steps
1. Sort the Meeting Intervals: Sort the intervals based on their start times.
2. Initialize a Min-Heap: Create a min-heap to track the end times of meetings currently using rooms.
3. Iterate Through the Meetings:
• For each meeting, check if it starts after the earliest ending meeting in the heap.
• If it does, remove that meeting from the heap (a room has been freed).
• Add the current meeting’s end time to the heap.
4. Return the Size of the Heap: The size of the heap at the end will represent the minimum number of rooms required.
import java.util.Arrays;
import java.util.PriorityQueue;
public class Solution {
public int minMeetingRooms(int[][] intervals) {
// If there are no meetings, return 0
if (intervals.length == 0) return 0;
// Sort the meetings in increasing order of their start time
Arrays.sort(intervals, (a, b) -> a[0] - b[0]);
// Min-heap to keep track of end times of meetings
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
// Add the first meeting's end time to the heap
minHeap.offer(intervals[0][1]);
// Iterate through the remaining meetings
for (int i = 1; i < intervals.length; i++) {
// If the meeting starts after the earliest meeting ends, free a room
if (intervals[i][0] >= minHeap.peek()) {
minHeap.poll(); // Remove the room that got free
}
// Add the current meeting's end time to the heap
minHeap.offer(intervals[i][1]);
}
// The size of the heap tells us the minimum rooms required
return minHeap.size();
}
Line-by-Line Explanation
- Initialize Variables
if (intervals.length == 0) return 0;
• If there are no meetings, return 0 since no rooms are needed.
2. Sort the Intervals
Arrays.sort(intervals, (a, b) -> a[0] - b[0]);
• We sort the meetings by their start time. This helps us to process meetings in the order they start, which is essential for managing overlaps.
3. Initialize Min-Heap
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
- We create a min-heap to track the end times of the meetings currently using rooms. The heap allows us to efficiently access the meeting that ends the soonest.
4. Add First Meeting’s End Time
minHeap.offer(intervals[0][1]);
- We add the end time of the first meeting to the heap, as it requires a room.
5. Iterate Through Remaining Meetings:
for (int i = 1; i < intervals.length; i++) {
- We loop through the remaining meetings starting from the second one.
6. Check for Room Availability:
if (intervals[i][0] >= minHeap.peek()) {
minHeap.poll(); // Remove the room that got free
}
• If the current meeting starts after the earliest ending meeting (i.e., the root of the heap), it means a room is free, and we can remove that room from the heap.
7. Add Current Meeting’s End Time:
minHeap.offer(intervals[i][1]);
- We then add the current meeting’s end time to the heap, as it occupies a room.
8. Return Number of Rooms:
return minHeap.size();
Why This Code Was Coded This Way
• Efficiency: The sorting step and the use of a priority queue ensure that the algorithm runs efficiently with O(n \log n) time complexity and O(n) space complexity.
• Simplicity in Managing Overlaps: The use of a priority queue allows easy management of end times, enabling quick checks on room availability.
• Scalability: This approach is scalable and can handle larger input sizes effectively due to its linearithmic time complexity.
Overall, the chosen strategy is well-suited for the problem, providing an optimal solution that can be generalized to similar interval scheduling problems.
When we encounter a new meeting that starts after the earliest meeting has ended, we remove a room from the priority queue (min-heap) because it indictates that one of the previously occupied rooms has become available.