Skip to content

Commit 2df4b2d

Browse files
committed
feat(algorithms, intervals, meeting rooms): meeting rooms
1 parent b79630f commit 2df4b2d

File tree

8 files changed

+168
-122
lines changed

8 files changed

+168
-122
lines changed
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# Meeting Rooms
2+
3+
Given an 2D integer array A of size N x 2 denoting time intervals of different meetings.
4+
5+
Where:
6+
7+
A[i][0] = start time of the ith meeting.
8+
A[i][1] = end time of the ith meeting.
9+
10+
Find the minimum number of conference rooms required so that all meetings can be done.
11+
12+
> Note :- If a meeting ends at time t, another meeting starting at time t can use the same conference room
13+
14+
```plain
15+
Input Format
16+
The only argument given is the matrix A.
17+
```
18+
19+
```plain
20+
Output Format
21+
Return the minimum number of conference rooms required so that all meetings can be done.
22+
```
23+
24+
```plain
25+
Example Input
26+
Input 1:
27+
28+
A = [ [0, 30]
29+
[5, 10]
30+
[15, 20]
31+
]
32+
33+
Input 2:
34+
35+
A = [ [1, 18]
36+
[18, 23]
37+
[15, 29]
38+
[4, 15]
39+
[2, 11]
40+
[5, 13]
41+
]
42+
43+
Example Output
44+
Output 1:
45+
46+
2
47+
Output 2:
48+
49+
4
50+
```
51+
52+
```plain
53+
Example Explanation
54+
Explanation 1:
55+
56+
Meeting one can be done in conference room 1 form 0 - 30.
57+
Meeting two can be done in conference room 2 form 5 - 10.
58+
Meeting three can be done in conference room 2 form 15 - 20 as it is free in this interval.
59+
Explanation 2:
60+
61+
Meeting one can be done in conference room 1 from 1 - 18.
62+
Meeting five can be done in conference room 2 from 2 - 11.
63+
Meeting four can be done in conference room 3 from 4 - 15.
64+
Meeting six can be done in conference room 4 from 5 - 13.
65+
Meeting three can be done in conference room 2 from 15 - 29 as it is free in this interval.
66+
Meeting two can be done in conference room 4 from 18 - 23 as it is free in this interval.
67+
```
68+
69+
## Examples
70+
71+
![Example 1](./images/examples/meeting_rooms_example_1.png)
72+
![Example 2](./images/examples/meeting_rooms_example_2.png)
73+
![Example 3](./images/examples/meeting_rooms_example_3.png)
74+
75+
## Solution
76+
77+
### Naive Approach
78+
79+
The naive approach to solve this problem is to check each meeting’s interval with every other meeting’s interval to
80+
determine if a room is available or a new room needs to be allocated. Though this approach is easy, it becomes
81+
inefficient when there are a large number of meetings and their time intervals overlap. In the worst-case scenario, we
82+
would need to allocate a new room for each meeting, resulting in a time complexity of O(n^2), where n is the number of
83+
meetings. Therefore, while this approach can work for small inputs, it is not scalable and becomes impractical for
84+
larger inputs. So, let’s devise an optimized approach to solve this problem.
85+
86+
### Solution summary
87+
88+
To recap, the solution to this problem can be divided into the following four parts:
89+
90+
1. We sort the meeting intervals based on their start times.
91+
2. We maintain a min-heap and insert the end time of the first meeting.
92+
3. For each meeting, we check the following:
93+
- If the minimum end time is less than or equal to the start time of a new meeting, then a room is available.
94+
- If a meeting room is unavailable, a new room is allocated for the meeting.
95+
4. The size of the heap after all meetings have been processed is equal to the minimum number of rooms required to
96+
accommodate all meetings.
97+
98+
#### Time Complexity
99+
100+
Since we are sorting the intervals and also maintaining the heap, we have to take the time taken by these two processes
101+
into account. The sorting of the meeting intervals according to the start time takes `O(n × log(n))`. Now, for the heap,
102+
we know that we add the end time of a meeting if there is no room available for the meeting. Since the cost of adding an
103+
element to a heap is `O(log(size of heap))` in the worst case, the cost of adding to the heap grows in the following way:
104+
105+
log(1) + log(2) + log(3) + ... + log(n) = log(n!) = O(n log(n))
106+
107+
According to `Stirling’s approximation`, the sum of the above equation is O(n * log(n)). So, the total time complexity
108+
becomes O(n log(n)) + O(n log(n)) = O(n log(n)).
109+
110+
> Stirling's approximation is a mathematical formula that provides an approximate value for the factorial of a large
111+
> positive integer
112+
113+
#### Space Complexity
114+
115+
The space complexity of this solution is O(n). This is because we are building a min-heap that, in the worst case,
116+
can have all the input elements. Therefore, the space required to compute this solution would be O(n).

puzzles/meeting_rooms/__init__.py renamed to algorithms/intervals/meeting_rooms/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,13 @@ def find_minimum_meeting_rooms_priority_queue(meetings: List[List[int]]) -> int:
5858
for start, end in meetings[1:]:
5959
# top of the heap is the meeting that will end soonest, we can remove it if it ends before the next meeting
6060
# starts
61+
# Check if the minimum element of the heap (i.e., the earliest ending meeting) is free
6162
if rooms[0] <= start:
63+
# If the room is free, extract the earliest ending meeting and add the ending time of the current meeting
6264
heapq.heappop(rooms)
6365

66+
# Add the ending time of the current meeting to the heap
6467
heapq.heappush(rooms, end)
6568

69+
# The size of the heap tells us the number of rooms allocated
6670
return len(rooms)
79.1 KB
Loading
90.7 KB
Loading
85.2 KB
Loading
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import unittest
2+
from typing import List
3+
from parameterized import parameterized
4+
from . import find_minimum_meeting_rooms, find_minimum_meeting_rooms_priority_queue
5+
6+
7+
class MinimumMeetingRoomsTestCase(unittest.TestCase):
8+
@parameterized.expand(
9+
[
10+
([], 0),
11+
([[0, 30], [5, 10], [15, 20]], 2),
12+
([[1, 18], [18, 23], [15, 29], [4, 15], [2, 11], [5, 13]], 4),
13+
([[2, 8], [3, 4], [3, 9], [5, 11], [8, 20], [11, 15]], 3),
14+
([[1, 7], [2, 6], [3, 7], [4, 8], [5, 8], [2, 9], [1, 8]], 7),
15+
([[1, 6], [4, 8], [1, 5], [6, 8], [8, 11], [8, 9], [5, 10]], 3),
16+
([[1, 3], [2, 6], [8, 10], [9, 15], [12, 14]], 2),
17+
([[1, 2], [4, 6], [3, 4], [7, 8]], 1),
18+
([[1, 7], [2, 6], [3, 7], [4, 8], [5, 8]], 5),
19+
([[1, 2], [1, 2], [1, 2]], 3),
20+
]
21+
)
22+
def test_find_minimum_meeting_rooms(self, meetings: List[List[int]], expected: int):
23+
actual = find_minimum_meeting_rooms(meetings)
24+
self.assertEqual(expected, actual)
25+
26+
@parameterized.expand(
27+
[
28+
([], 0),
29+
([[0, 30], [5, 10], [15, 20]], 2),
30+
([[1, 18], [18, 23], [15, 29], [4, 15], [2, 11], [5, 13]], 4),
31+
([[2, 8], [3, 4], [3, 9], [5, 11], [8, 20], [11, 15]], 3),
32+
([[1, 7], [2, 6], [3, 7], [4, 8], [5, 8], [2, 9], [1, 8]], 7),
33+
([[1, 6], [4, 8], [1, 5], [6, 8], [8, 11], [8, 9], [5, 10]], 3),
34+
([[1, 3], [2, 6], [8, 10], [9, 15], [12, 14]], 2),
35+
([[1, 2], [4, 6], [3, 4], [7, 8]], 1),
36+
([[1, 7], [2, 6], [3, 7], [4, 8], [5, 8]], 5),
37+
([[1, 2], [1, 2], [1, 2]], 3),
38+
]
39+
)
40+
def test_find_minimum_meeting_rooms_priority_queue(
41+
self, meetings: List[List[int]], expected: int
42+
):
43+
actual = find_minimum_meeting_rooms_priority_queue(meetings)
44+
self.assertEqual(expected, actual)
45+
46+
47+
if __name__ == "__main__":
48+
unittest.main()

puzzles/meeting_rooms/README.md

Lines changed: 0 additions & 71 deletions
This file was deleted.

puzzles/meeting_rooms/test_min_meeting_rooms.py

Lines changed: 0 additions & 51 deletions
This file was deleted.

0 commit comments

Comments
 (0)