Meeting Rooms II in Python with O(n log n) Time Complexity


Given an array consisting of meeting time intervals, which are represented by the start and end times ([s0, e0], [s1, e1], ...], determine the minimum number of meeting rooms needed in order to be able to accommodate all meetings at every moment of time.


Example:

Input: [[5, 10], [0, 30], [15, 20]]
Output: 2
Explanation: 1st and 3rd meetings can be assigned to the first room
             2nd meeting can be assigned to room 2

 

Note:

  1. You may assume the interval's end point is always greater than its start point.
  2. Intervals like [1,2] and [2,3] have borders "touching" but they don't overlap.

Your algorithm should run in O(n log n) time and use O(n) extra space.


Understanding the Problem

The core challenge of this problem is to determine the minimum number of meeting rooms required to accommodate all meetings without any overlap. This problem is significant in scheduling and resource allocation scenarios, such as conference room booking systems.

Potential pitfalls include misunderstanding the overlap conditions and not accounting for meetings that end exactly when another starts.

Approach

To solve this problem, we can use a greedy algorithm with a priority queue (min-heap). Here's a step-by-step approach:

Naive Solution

A naive solution would involve checking each meeting against all others to see if they overlap, which would result in a time complexity of O(n^2). This is not optimal for large inputs.

Optimized Solution

An optimized solution involves sorting the meetings by their start times and using a min-heap to keep track of the end times of ongoing meetings. This allows us to efficiently determine the minimum number of rooms required.

Algorithm

1. Sort the meetings by their start times.

2. Initialize a min-heap to keep track of end times of meetings currently using a room.

3. Iterate through the sorted meetings:

Code Implementation

import heapq

def minMeetingRooms(intervals):
    # If there are no meetings, we don't need any rooms
    if not intervals:
        return 0

    # Initialize a heap.
    free_rooms = []

    # Sort the meetings in increasing order of their start time.
    intervals.sort(key=lambda x: x[0])

    # Add the first meeting. We have to give a new room to the first meeting.
    heapq.heappush(free_rooms, intervals[0][1])

    # For all the remaining meeting rooms
    for i in intervals[1:]:

        # If the room due to free up the earliest is free, assign that room to this meeting.
        if free_rooms[0] <= i[0]:
            heapq.heappop(free_rooms)

        # If a new room is to be assigned, then also we add to the heap.
        # If an old room is allocated, then also we have to add to the heap with updated end time.
        heapq.heappush(free_rooms, i[1])

    # The size of the heap tells us the minimum rooms required for all the meetings.
    return len(free_rooms)

# Example usage
intervals = [[5, 10], [0, 30], [15, 20]]
print(minMeetingRooms(intervals))  # Output: 2

Complexity Analysis

The time complexity of this approach is O(n log n) due to the sorting step and the heap operations. The space complexity is O(n) because we store all the meeting end times in the heap.

Edge Cases

Consider edge cases such as:

Testing

To test the solution comprehensively, include a variety of test cases:

Thinking and Problem-Solving Tips

When approaching such problems, it's essential to:

Conclusion

In this blog post, we discussed the problem of determining the minimum number of meeting rooms required to accommodate all meetings. We explored a naive solution and an optimized solution using a min-heap. We also analyzed the complexity and discussed edge cases and testing strategies.

Understanding and solving such problems is crucial for developing efficient algorithms and improving problem-solving skills. Keep practicing and exploring further!

Additional Resources

For further reading and practice problems, consider the following resources: