Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 110 additions & 0 deletions 253. Meeting Rooms II/253. Meeting Rooms II.md
Original file line number Diff line number Diff line change
@@ -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, [])
Copy link
Copy Markdown

@Fuminiton Fuminiton Aug 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

osモジュールにtimesがあるので別の名前が良いかと思います。

os.times()
現在の全体的なプロセス時間を返します。返り値は 5 個の属性を持つオブジェクトになります:

https://docs.python.org/ja/3.13/library/os.html#os.times

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

その観点は見落としていました。ありがとうございます。

Copy link
Copy Markdown

@Kaichi-Irie Kaichi-Irie Sep 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

自分も知りませんでした。ありがとうございます。

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
Comment on lines +95 to +96
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ROOM_REQUIRED, ROOM_RELEASED のような定数に置くのも一案かと思います。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

個人的には定数にするなら絶対値は同じなので一つかなという気がします。コメントありがとうございます。

NUM_ROOMS_PER_MEETING = 1

events.append((start, +NUM_ROOMS_PER_MEETING))  # secure room(s)
events.append((end, -NUM_ROOMS_PER_MEETING))  # free room(s)


# if start == end, end (-1) comes before start (+1),
# so a room is freed before being reused.
events.sort()

min_num_rooms = 0
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optional: required_rooms などもありですかね。

num_occupied_rooms = 0
for _, delta in events:
num_occupied_rooms += delta
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

好みだと思いますが、
eventがstartであることと、eventがstartだから1を足す話は別な気がするので、分けた方が親切な気がしました。
具体的には、以下のようなイメージです。

        MEETING_START = 1
        MEETING_END = -1

        events = []
        for start_time, end_time in intervals:
            events.append((start_time, MEETING_START))
            events.append((end_time, MEETING_END))
        
        num_occupied = 0
        num_needed = 0
        events.sort()
        for event_time, event_type in events:
            if event_type == MEETING_END:
                num_occupied -= 1
                continue
            num_occupied += 1
            num_needed = max(num_needed, num_occupied)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

個人的には違う感覚だなと思いました。
というのもMEETING_STARTとMEETING_ENDの大小関係がソートに影響してアルゴリズムが正しく動くかを左右します。単に部屋数の増減を直接書けば1と-1は意味を持ちますが(コメントで補足すべきと思います)、MEETING_STARTの値は意味を持っていない(値に必然性がない)ためです。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

回答ありがとうございます。

自分はeventsを(時間, 会議が始まる or 終わる)と捉えていたのですが、tokuhirat さんは初めから(時間, 必要な部屋数が1つ増えるかor1つ減るか)で考えていたということですね。

納得しました。よくよく考えると、tokuhirat さんのやり方の方がシンプルで良いと思いました。ある会議で部屋数を複数個使うみたいな状況にも対応できますし。

min_num_rooms = max(min_num_rooms, num_occupied_rooms)
return min_num_rooms
```

4分,3分,3分で3回Accept