Design Gurus Logo
Blind 75
Solution: Meeting Rooms II

Problem Statement

Given an array of meeting intervals where intervals[i] = [start<sub>i</sub>, end<sub>i</sub>], return the minimum number of meeting rooms needed so that no meetings overlap.

Examples

Example 1:

  • Input: intervals = [[10, 15], [20, 25], [30, 35]]
  • Expected Output: 1
  • Justification: There are no overlapping intervals in the given list. So, only 1 meeting room is enough for all the meetings.

Example 2:

  • Input: intervals = [[10, 20], [15, 25], [24, 30], [5, 14], [22, 28], [1, 4], [27, 35]]
  • Expected Output: 3
  • Justification: Let's see how many meetings overlap at the same time:
    • [1, 4] starts first.
    • Then [5, 14] begins, no overlap yet.
    • [10, 20] overlaps with [5, 14]
    • [15, 25] overlaps with [10, 20]
    • [22, 28] overlaps with [15, 25]
    • [24, 30] overlaps with both [22, 28] and [15, 25]
    • [27, 35] overlaps with [24, 30]

Example 3:

  • Input: intervals = [[10, 20], [20, 30]]
  • Expected Output: 1
  • Justification: The end time of the first meeting is the same as the start time of the second meeting. So, one meeting can be scheduled right after the other in the same room.

Constraints:

  • 1 <= intervals.length <= 10<sup>4</sup>
  • 0 <= start<sub>i</sub> < end<sub>i</sub> <= 10<sup>6</sup>

Solution

To find the minimum number of meeting rooms required, we sort all the meetings by their start times. This allows us to always process meetings in chronological order. Then, we use a min-heap (priority queue) to track the end times of meetings that are currently using rooms. The heap helps us know which room becomes available the earliest.

For each meeting, we compare its start time with the earliest ending meeting (top of the heap). If the current meeting can reuse a room (its start time is greater than or equal to the earliest end time), we remove the ended meeting from the heap. Regardless, we then add the current meeting’s end time to the heap. At the end, the size of the heap tells us how many rooms were used at the same time — which is the minimum number of rooms required.

Step-by-Step Algorithm

  1. Check if there are no meetings:

    • If the input array intervals is empty, return 0 since no rooms are needed.
  2. Sort the meetings by their start times:

    • Use Arrays.sort() and sort all intervals based on the first element (start time).
  3. Create a min-heap (priority queue):

    • Initialize a PriorityQueue to keep track of ongoing meetings.
    • This heap will store the end times of meetings currently using a room.
    • The meeting that ends the earliest will always be at the top.
  4. Add the first meeting's end time to the heap:

    • This allocates the first room for the first meeting.
  5. Process the remaining meetings one by one:

    • For each meeting from the second onwards:
      • Compare its start time with the top of the heap (the earliest end time).
      • If the current meeting starts after or exactly when the earliest meeting ends:
        • Remove the top value from the heap (free up the room).
      • Add the current meeting’s end time to the heap (assign a room).
  6. Return the number of rooms used:

    • After processing all meetings, return the size of the heap.
    • This number represents the maximum number of rooms used at the same time, which is the minimum number of rooms required.

Algorithm Walkthrough

Step 1: Sort the intervals by start time

Sorted intervals:

[[1, 4], [5, 14], [10, 20], [15, 25], [22, 28], [24, 30], [27, 35]]

This ensures that we always process meetings in the order they begin.

Step 2: Initialize min-heap and add end time of the first meeting

  • We start by booking one room for the first meeting [1, 4].
  • We store its end time (4) in the heap to track when this room becomes free.
  • At this point, only one meeting is scheduled.

Heap status: [4]

Step 3: Process remaining meetings (from index 1 onward)

  • intervals[1] = [5, 14]

    • Start = 5
    • Earliest end in heap = 4
    • 5 >= 4 → ✅ Room is free
    • Remove 4 from heap (meeting [1, 4] has ended)
    • Add 14 to heap (allocate room for [5, 14])
    • Heap = [14]
  • intervals[2] = [10, 20]

    • Start = 10
    • Heap top = 14
    • 10 >= 14 → ❌ false
    • Room not free → Allocate new room
    • Add 20 to heap
    • Heap = [14, 20]
  • intervals[3] = [15, 25]

    • Start = 15
    • Heap top = 14
    • 15 >= 14 → ✅
    • Remove 14 from heap (free a room)
    • Add 25 to heap
    • Heap = [20, 25]
  • intervals[4] = [22, 28]

    • Start = 22
    • Heap top = 20
    • 22 >= 20 → ✅
    • Remove 20 from heap
    • Add 28 to heap
    • Heap = [25, 28]
  • intervals[5] = [24, 30]

    • Start = 24
    • Heap top = 25
    • 24 >= 25 → ❌
    • Need a new room
    • Add 30 to heap
    • Heap = [25, 28, 30]
  • intervals[6] = [27, 35]

    • Start = 27
    • Heap top = 25
    • 27 >= 25 → ✅
    • Remove 25 from heap
    • Add 35 to heap
    • Heap = [28, 30, 35]

Final Step: Return heap size

  • Final heap: [28, 30, 35]
  • Size = 3

This means 3 meeting rooms were used at peak overlap.

Code

Python3
Python3

Complexity Analysis

  • Time Complexity: The time complexity of our algorithm is O(N \log N), where (N) is the number of intervals. This is because we're sorting the intervals once and then using priority queues to process them.

  • Space Complexity: The space complexity is O(N) as we're storing all intervals in the worst case.