253. Meeting Rooms II - Explanation
Description
Given an array of meeting time interval objects consisting of start and end times [[start_1,end_1],[start_2,end_2],...] (start_i < end_i), find the minimum number of rooms required to schedule all meetings without any conflicts.
Note: (0,8),(8,10) is NOT considered a conflict at 8.
Example 1:
Input: intervals = [(0,40),(5,10),(15,20)]
Output: 2Explanation:
room1: (0,40)
room2: (5,10),(15,20)
Example 2:
Input: intervals = [(4,9)]
Output: 1Constraints:
0 <= intervals.length <= 5000 <= intervals[i].start < intervals[i].end <= 1,000,000
Topics
Recommended Time & Space Complexity
You should aim for a solution with O(nlogn) time and O(n) space, where n is the size of the input array.
Hint 1
Try to visualize the meetings as line segments on a number line representing start and end times. The number of rooms required is the maximum number of overlapping meetings at any point on the number line. Can you think of a way to determine this efficiently?
Hint 2
We create two arrays, start and end, containing the start and end times of all meetings, respectively. After sorting both arrays, we use a two-pointer based approach. How do you implement this?
Hint 3
We use two pointers, s and e, for the start and end arrays, respectively. We also maintain a variable count to track the current number of active meetings. At each iteration, we increment s while the start time is less than the current end time and increase count, as these meetings must begin before the earliest ongoing meeting ends.
Hint 4
Then, we increment e and decrement count as a meeting has ended. At each step, we update the result with the maximum value of active meetings stored in count.
Prerequisites
Before attempting this problem, you should be comfortable with:
- Sorting - Required to process meetings in order by start time
- Min Heap / Priority Queue - Used to efficiently track the earliest ending meeting room
- Intervals - Understanding how to detect and handle overlapping time intervals
- Sweep Line Algorithm - Alternative approach using event processing on a timeline
- Two Pointers - Used in the approach that separates start and end times
1. Min Heap
Intuition
We want to find the minimum number of meeting rooms required so that no meetings overlap.
A useful way to think about this is:
- each meeting needs a room from its start time to its end time
- if a meeting starts after or at the same time another meeting ends, they can share the same room
- otherwise, we need a new room
To efficiently track room availability, we use a min heap:
- the heap stores the end times of meetings currently occupying rooms
- the smallest end time is always at the top, representing the room that frees up the earliest
As we process meetings in order of start time:
- if the earliest-ending meeting finishes before the current one starts, we can reuse that room
- otherwise, we must allocate a new room
The maximum size the heap reaches is the number of rooms needed.
Algorithm
- Sort all meetings by their start time.
- Initialize an empty min heap
min_heapto store meeting end times. - Iterate through each meeting in sorted order:
- If the heap is not empty and the earliest end time (
min_heap[0]) is less than or equal to the current meeting’s start:- pop the top of the heap (reuse that room)
- Push the current meeting’s end time into the heap (occupy a room).
- After processing all meetings:
- the size of the heap represents the minimum number of rooms required
- Return the size of the heap.
"""
Definition of Interval:
class Interval(object):
def __init__(self, start, end):
self.start = start
self.end = end
"""
class Solution:
def minMeetingRooms(self, intervals: List[Interval]) -> int:
intervals.sort(key=lambda x: x.start)
min_heap = []
for interval in intervals:
if min_heap and min_heap[0] <= interval.start:
heapq.heappop(min_heap)
heapq.heappush(min_heap, interval.end)
return len(min_heap)Time & Space Complexity
- Time complexity:
- Space complexity:
2. Sweep Line Algorithm
Intuition
We want to find the minimum number of meeting rooms needed so that no meetings overlap.
Instead of assigning rooms directly, we can look at the problem as a timeline:
- every meeting starts at a certain time
- every meeting ends at a certain time
At any point in time, the number of rooms required is simply:
the number of meetings happening at that moment
The sweep line technique helps us track how this number changes over time by processing all start and end events in order.
Algorithm
- Create a map
mpto record changes in the number of active meetings:- for each meeting:
- increment
mp[start](a meeting starts) - decrement
mp[end](a meeting ends)
- increment
- for each meeting:
- Initialize:
prev=0to track the number of ongoing meetingsres=0to store the maximum number of simultaneous meetings
- Iterate through all time points in
mpin sorted order: - At each time
i:- update the current number of meetings:
prev+=mp[i]
- update the answer:
res=max(res, prev)
- update the current number of meetings:
- After processing all events, return
res.
"""
Definition of Interval:
class Interval(object):
def __init__(self, start, end):
self.start = start
self.end = end
"""
class Solution:
def minMeetingRooms(self, intervals: List[Interval]) -> int:
mp = defaultdict(int)
for i in intervals:
mp[i.start] += 1
mp[i.end] -= 1
prev = 0
res = 0
for i in sorted(mp.keys()):
prev += mp[i]
res = max(res, prev)
return resTime & Space Complexity
- Time complexity:
- Space complexity:
3. Two Pointers
Intuition
We want to find the minimum number of meeting rooms required so that no meetings overlap.
Instead of tracking whole intervals, we can separate the problem into two simpler timelines:
- one list of all start times
- one list of all end times
If we process these timelines in order:
- whenever a meeting starts before another one ends, we need a new room
- whenever a meeting ends before or at the same time another starts, a room becomes free
By moving two pointers over the sorted start and end times, we can track how many meetings are happening at the same time.
The maximum number of simultaneous meetings at any moment is exactly the number of rooms we need.
Algorithm
- Create two arrays:
start→ all meeting start times, sortedend→ all meeting end times, sorted
- Initialize:
s=0→ pointer for start timese=0→ pointer for end timescount=0→ current number of ongoing meetingsres=0→ maximum number of rooms needed
- While there are still meetings to process (
s< number of meetings): - If
start[s]<end[e]:- a new meeting starts before the earliest one ends
- increment
count(need one more room) - move
sforward
- Else:
- a meeting has ended
- decrement
count(a room is freed) - move
eforward
- Update
res=max(res, count)after each step. - Return
res.
"""
Definition of Interval:
class Interval(object):
def __init__(self, start, end):
self.start = start
self.end = end
"""
class Solution:
def minMeetingRooms(self, intervals: List[Interval]) -> int:
start = sorted([i.start for i in intervals])
end = sorted([i.end for i in intervals])
res = count = 0
s = e = 0
while s < len(intervals):
if start[s] < end[e]:
s += 1
count += 1
else:
e += 1
count -= 1
res = max(res, count)
return resTime & Space Complexity
- Time complexity:
- Space complexity:
4. Greedy
Intuition
We want to find the minimum number of meeting rooms required so that no meetings overlap.
Instead of thinking in terms of rooms directly, we can think in terms of events on a timeline:
- when a meeting starts, we need one more room
- when a meeting ends, one room is freed
So the problem reduces to:
What is the maximum number of meetings happening at the same time?
If we track how the number of active meetings changes over time, the maximum value we ever reach is exactly the number of rooms we need.
This greedy approach works by:
- converting each meeting into two events (start and end)
- sorting all events by time
- sweeping from left to right while counting active meetings
Algorithm
- Create an empty list
timeto store events. - For each meeting interval:
- add
(start, +1)→ meeting starts (need a room) - add
(end, -1)→ meeting ends (free a room)
- add
- Sort
time:- primarily by time
- secondarily by event type so that end events (
-1) are processed before start events (+1) at the same time
- Initialize:
count=0→ current number of ongoing meetingsres=0→ maximum number of rooms needed
- Traverse the sorted
timelist:- add the event value (
+1or-1) tocount - update
res=max(res, count)
- add the event value (
- After processing all events, return
res.
"""
Definition of Interval:
class Interval(object):
def __init__(self, start, end):
self.start = start
self.end = end
"""
class Solution:
def minMeetingRooms(self, intervals: List[Interval]) -> int:
time = []
for i in intervals:
time.append((i.start, 1))
time.append((i.end, -1))
time.sort(key=lambda x: (x[0], x[1]))
res = count = 0
for t in time:
count += t[1]
res = max(res, count)
return resTime & Space Complexity
- Time complexity:
- Space complexity:
Common Pitfalls
Using the Wrong Comparison for Room Reuse
When checking if a room can be reused, the condition should be earliest_end_time <= current_start, not <. A meeting ending at time t allows a room to be reused by a meeting starting at time t.
Forgetting to Sort Meetings Before Processing
The min heap and two pointer approaches only work correctly when meetings are sorted by start time. Without sorting, you cannot determine the correct order of room allocation.
Returning the Max Heap Size Instead of Tracking It
The heap size changes throughout processing. You need to track the maximum size the heap reaches during iteration, or simply return the final heap size if you only pop when reusing rooms.
Sign in to join the discussion