253. Meeting Rooms II - Explanation

Problem Link

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 days 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: 2

Explanation:
day1: (0,40)
day2: (5,10),(15,20)

Example 2:

Input: intervals = [(4,9)]

Output: 1

Constraints:

  • 0 <= intervals.length <= 500
  • 0 <= 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.


Company Tags

Please upgrade to NeetCode Pro to view company tags.



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

  1. Sort all meetings by their start time.
  2. Initialize an empty min heap min_heap to store meeting end times.
  3. Iterate through each meeting in sorted order:
  4. 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)
  5. Push the current meeting’s end time into the heap (occupy a room).
  6. After processing all meetings:
    • the size of the heap represents the minimum number of rooms required
  7. 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: O(nlogn)O(n \log n)
  • Space complexity: O(n)O(n)

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

  1. Create a map mp to record changes in the number of active meetings:
    • for each meeting:
      • increment mp[start] (a meeting starts)
      • decrement mp[end] (a meeting ends)
  2. Initialize:
    • prev = 0 to track the number of ongoing meetings
    • res = 0 to store the maximum number of simultaneous meetings
  3. Iterate through all time points in mp in sorted order:
  4. At each time i:
    • update the current number of meetings:
      • prev += mp[i]
    • update the answer:
      • res = max(res, prev)
  5. 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 res

Time & Space Complexity

  • Time complexity: O(nlogn)O(n \log n)
  • Space complexity: O(n)O(n)

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

  1. Create two arrays:
    • start → all meeting start times, sorted
    • end → all meeting end times, sorted
  2. Initialize:
    • s = 0 → pointer for start times
    • e = 0 → pointer for end times
    • count = 0 → current number of ongoing meetings
    • res = 0 → maximum number of rooms needed
  3. While there are still meetings to process (s < number of meetings):
  4. If start[s] < end[e]:
    • a new meeting starts before the earliest one ends
    • increment count (need one more room)
    • move s forward
  5. Else:
    • a meeting has ended
    • decrement count (a room is freed)
    • move e forward
  6. Update res = max(res, count) after each step.
  7. 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 res

Time & Space Complexity

  • Time complexity: O(nlogn)O(n \log n)
  • Space complexity: O(n)O(n)

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

  1. Create an empty list time to store events.
  2. For each meeting interval:
    • add (start, +1) → meeting starts (need a room)
    • add (end, -1) → meeting ends (free a room)
  3. Sort time:
    • primarily by time
    • secondarily by event type so that end events (-1) are processed before start events (+1) at the same time
  4. Initialize:
    • count = 0 → current number of ongoing meetings
    • res = 0 → maximum number of rooms needed
  5. Traverse the sorted time list:
    • add the event value (+1 or -1) to count
    • update res = max(res, count)
  6. 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 res

Time & Space Complexity

  • Time complexity: O(nlogn)O(n \log n)
  • Space complexity: O(n)O(n)

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.