diff --git a/253. Meeting Rooms II/253. Meeting Rooms II.md b/253. Meeting Rooms II/253. Meeting Rooms II.md new file mode 100644 index 0000000..5a90ba4 --- /dev/null +++ b/253. Meeting Rooms II/253. Meeting Rooms II.md @@ -0,0 +1,110 @@ +# 253. Meeting Rooms II +## STEP1 +- 何も見ずに解いてみる +- 252\. Meeting Rooms でみた累積和の考え方を使えば解ける。 +```python +class Solution: + MAX_TIME = 10 ** 6 + def minMeetingRooms(self, intervals: List[List[int]]) -> int: + time_to_num_rooms = [0] * (self.MAX_TIME + 1) + for start, end in intervals: + time_to_num_rooms[start] += 1 + time_to_num_rooms[end] -= 1 + + for i in range(1, len(time_to_num_rooms)): + time_to_num_rooms[i] += time_to_num_rooms[i - 1] + + return max(time_to_num_rooms) +``` + +- MAX_TIME ループするのは非効率なので座標圧縮する。 +```python +def coordinate_compression(coordinate: list[int]) -> dict[int, int]: + coordinate = sorted(set(coordinate)) + return {value: i for i, value in enumerate(coordinate)} + + +class Solution: + def minMeetingRooms(self, intervals: List[List[int]]) -> int: + times = sum(intervals, []) + time_to_index = coordinate_compression(times) + + index_to_num_rooms = [0] * (len(time_to_index) + 1) + for start_time, end_time in intervals: + start_index = time_to_index[start_time] + end_index = time_to_index[end_time] + index_to_num_rooms[start_index] += 1 + index_to_num_rooms[end_index] -= 1 + + for i in range(1, len(index_to_num_rooms)): + index_to_num_rooms[i] += index_to_num_rooms[i - 1] + return max(index_to_num_rooms) +``` +## STEP2 +### プルリクやドキュメントを参照 +- https://github.com/olsen-blue/Arai60/pull/57/files + > この問題を手で解くとして、解法の取りうる範囲の数字を全部挙げはじめたら結構驚くと思うんですよね。 + + 確かにその通りですね。 +- https://github.com/olsen-blue/Arai60/pull/57/files#r2030075157 + > (start, +1), (end, -1) からなる集合を作ってソートする + + なるほど、スマートな方法だと思った。ソートした際に同じ時刻があると −1 のおかげで end が先に来るようになっているのは見落としそう。 + - https://github.com/Mike0121/LeetCode/pull/28/files#r1633611163 + 同じ感覚でした。 + +```python +class Solution: + def minMeetingRooms(self, intervals: List[List[int]]) -> int: + events = [] + for start, end in intervals: + events.append((start, 1)) + events.append((end, -1)) + events.sort() + + min_rooms = 0 + num_occupied_rooms = 0 + for _, delta in events: + num_occupied_rooms += delta + min_rooms = max(min_rooms, num_occupied_rooms) + return min_rooms +``` +- https://github.com/shining-ai/leetcode/blob/main/arai60/54-60_others/56_253_Meeting%20Rooms%20II/level_5.py + - heap 使うの面白い。開始時刻が早い順に見ていき、heap にためている会議が終了している場合は解放でき新しい終了時刻を追加(部屋の数は増えない)。会議が終わっている部屋がない場合は新しい部屋を追加。room_end_time は短くなることはなく、会議室を使いまわせる場合には増加しないので、len(room_end_time) が必要な会議室の数になる。 + ```python + import heapq + + +class Solution: + def minMeetingRooms(self, intervals: List[List[int]]) -> int: + room_end_time = [] + for start, end in sorted(intervals): + if room_end_time and room_end_time[0] <= start: + heapq.heappop(room_end_time) + heapq.heappush(room_end_time, end) + return len(room_end_time) + ``` +## STEP3 +### 3回ミスなく書く +発生するイベントをソートする方法で書く。 +```python +class Solution: + def minMeetingRooms(self, intervals: List[List[int]]) -> int: + events = [] + for start, end in intervals: + events.append((start, 1)) # one more room needed + events.append((end, -1)) # one room freed + + # if start == end, end (-1) comes before start (+1), + # so a room is freed before being reused. + events.sort() + + min_num_rooms = 0 + num_occupied_rooms = 0 + for _, delta in events: + num_occupied_rooms += delta + min_num_rooms = max(min_num_rooms, num_occupied_rooms) + return min_num_rooms +``` + +4分,3分,3分で3回Accept