TL;DR
Min-heap of end times (or the two-pointer start/end sweep) β O(n log n) time, O(n) space.
Approach 1 β Brute force: count overlaps at every start
The number of rooms needed equals the peak number of simultaneous meetings, and that peak is always attained at some meetingβs start time (concurrency only increases at a start). So for every meeting, count how many meetings are running at the moment it starts, and take the max.
from typing import List
class Solution:
def minMeetingRooms(self, intervals: List[List[int]]) -> int:
rooms = 0
for i, (start_i, _) in enumerate(intervals):
running = 0
for start_j, end_j in intervals:
if start_j <= start_i < end_j:
running += 1
rooms = max(rooms, running)
return rooms
(Meeting i counts itself, since start_i <= start_i < end_i.)
Complexity: O(n^2) time, O(1) space.
At n = 10^4 thatβs 10^8 comparisons β too slow in Python, and it repeats work that a single sort would eliminate.
Approach 2 β Sort + min-heap of end times
The insight: process meetings in start order and simulate room assignment. The only room worth checking for reuse is the one whose meeting ends earliest β if even that one isnβt free, none are. A min-heap keyed on end time hands you exactly that room in O(log n).
import heapq
from typing import List
class Solution:
def minMeetingRooms(self, intervals: List[List[int]]) -> int:
intervals.sort(key=lambda it: it[0])
ends: List[int] = [] # min-heap of end times of occupied rooms
for start, end in intervals:
if ends and ends[0] <= start:
heapq.heapreplace(ends, end) # reuse the freed room
else:
heapq.heappush(ends, end) # need a new room
return len(ends)
Walkthrough on [[0,30],[5,10],[15,20]] (already sorted by start):
[0,30]: heap empty β push 30. Heap [30], 1 room.
[5,10]: earliest end is 30 > 5 β no room free β push 10. Heap [10, 30], 2 rooms.
[15,20]: earliest end is 10 <= 15 β reuse that room, replace 10 with 20. Heap [20, 30], still 2 rooms.
- Answer: heap size
2.
Complexity: O(n log n) time (sort + one heap op per meeting), O(n) space for the heap.
Approach 3 β Two pointers over sorted starts and ends
The insight: you never need to know which room a meeting uses β only the running count. Strip the intervals into two independent sorted arrays, all starts and all ends, and replay time: each start is +1 room unless some end has already occurred to offset it.
from typing import List
class Solution:
def minMeetingRooms(self, intervals: List[List[int]]) -> int:
starts = sorted(s for s, _ in intervals)
ends = sorted(e for _, e in intervals)
rooms = best = 0
e = 0
for s in starts:
while e < len(ends) and ends[e] <= s:
rooms -= 1
e += 1
rooms += 1
best = max(best, rooms)
return best
Walkthrough on [[1,4],[2,5],[3,6]]: starts = [1,2,3], ends = [4,5,6].
s = 1: no end <= 1 β rooms = 1.
s = 2: earliest end 4 > 2 β rooms = 2.
s = 3: earliest end 4 > 3 β rooms = 3.
- Peak is
3 β matching the example.
Pairing which start goes with which end doesnβt matter: only the counts of starts and ends before each moment do.
Complexity: O(n log n) time, O(n) space for the two arrays.
Common pitfalls
- Boundary reuse: a room ending at
t is free for a meeting starting at t, so the tests are ends[0] <= start / ends[e] <= s. Using < overcounts rooms for back-to-back meetings.
- Sorting the intervals but comparing each new meeting against the most recently added room instead of the earliest-ending one β thatβs what the heap ordering is for.
- Trying to reduce this to Meeting Rooms I logic (adjacent-pair checks) β pairwise non-overlap tells you if 1 room suffices, but it canβt count the peak.
- In the two-pointer version, popping ends with a separate loop after incrementing rooms β frees must be processed before the +1 or touching meetings inflate the peak.
Pattern takeaway
When an intervals problem asks βhow many at once?β rather than βdo any overlap?β, sort by start and maintain the set of active intervals β a min-heap on end time if you need to interact with the earliest-finishing one, or the decomposed starts/ends sweep if only the count matters. Peak concurrency is the size that active set reaches.