From c4b77f9a862d1e36975786ce673037590dc30a5b Mon Sep 17 00:00:00 2001 From: Yusuke Katsuki Date: Mon, 14 Apr 2025 16:03:36 -0400 Subject: [PATCH 1/5] Step1 --- 0252_Meeting_Rooms/solution_ja.md | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/0252_Meeting_Rooms/solution_ja.md b/0252_Meeting_Rooms/solution_ja.md index 374e0e1..78d71d1 100644 --- a/0252_Meeting_Rooms/solution_ja.md +++ b/0252_Meeting_Rooms/solution_ja.md @@ -1,20 +1,37 @@ ## Problem + // The URL of the problem ## Step 1 -5分程度答えを見ずに考えて、手が止まるまでやってみる。 + +5 分程度答えを見ずに考えて、手が止まるまでやってみる。 何も思いつかなければ、答えを見て解く。ただし、コードを書くときは答えを見ないこと。 動かないコードも記録する。 -正解したら一旦OK。思考過程もメモする。 +正解したら一旦 OK。思考過程もメモする。 ### Approach -* -```java +- 会議の開始時刻で昇順にソートする +- 会議を走査し、次の会議の開始時刻が現在の会議の終了時刻よりも早い場合 false を返す +```java +class Solution { + public boolean canAttendMeetings(int[][] intervals) { + Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0])); + for (int i = 0; i < intervals.length - 1; i++) { + int currentEnd = intervals[i][1]; + int nextStart = intervals[i + 1][0]; + if (nextStart < currentEnd) { + return false; + } + } + return true; + } +} ``` ## Step 2 + 他の方が描いたコードを見て、参考にしてコードを書き直してみる。 参考にしたコードのリンクは貼っておく。 読みやすいことを意識する。 @@ -25,8 +42,9 @@ ``` ## Step 3 + 今度は、時間を測りながら、もう一回書く。 -アクセプトされたら消すを3回連続できたら問題はOK。 +アクセプトされたら消すを 3 回連続できたら問題は OK。 ```java From 77e134d30d643e4253645df8155727d8abf3f5e0 Mon Sep 17 00:00:00 2001 From: Yusuke Katsuki Date: Thu, 17 Apr 2025 15:28:23 -0400 Subject: [PATCH 2/5] Add URL --- 0252_Meeting_Rooms/solution_ja.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/0252_Meeting_Rooms/solution_ja.md b/0252_Meeting_Rooms/solution_ja.md index 78d71d1..56007a8 100644 --- a/0252_Meeting_Rooms/solution_ja.md +++ b/0252_Meeting_Rooms/solution_ja.md @@ -1,6 +1,6 @@ ## Problem -// The URL of the problem +https://leetcode.com/problems/meeting-rooms/ ## Step 1 From 24837ebacfdcdd29bcd2839222fcb211b0117c38 Mon Sep 17 00:00:00 2001 From: Yusuke Katsuki Date: Fri, 18 Apr 2025 16:39:34 -0400 Subject: [PATCH 3/5] Step2 and 3 --- 0252_Meeting_Rooms/solution_ja.md | 103 +++++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 3 deletions(-) diff --git a/0252_Meeting_Rooms/solution_ja.md b/0252_Meeting_Rooms/solution_ja.md index 56007a8..9a38f54 100644 --- a/0252_Meeting_Rooms/solution_ja.md +++ b/0252_Meeting_Rooms/solution_ja.md @@ -11,8 +11,8 @@ https://leetcode.com/problems/meeting-rooms/ ### Approach -- 会議の開始時刻で昇順にソートする -- 会議を走査し、次の会議の開始時刻が現在の会議の終了時刻よりも早い場合 false を返す +- 所与の配列を会議の開始時刻で昇順にソートする +- 会議を走査し、次の会議が、現在の会議終了前に始まる場合 false を返す ```java class Solution { @@ -37,8 +37,92 @@ class Solution { 読みやすいことを意識する。 他の解法も考えみる。 +### Approach 1. 会議を開始時刻で Sort し、次と被ってないかチェックする方法 + +時間計算量: O(n log n) - sorting +空間計算量: O(n) - copy of intervals + +- https://github.com/Mike0121/LeetCode/pull/27/files#r1633298146 + - > 入力データを破壊するのは、やや違和感があります + - たしかによくよく考えると呼び出し元のコードにも影響を及ぼす可能性がありよくないなと思った + ```java +class Solution { + public boolean canAttendMeetings(int[][] intervals) { + int[][] sortedIntervals = Arrays.copyOf(intervals, intervals.length); + Arrays.sort(sortedIntervals, Comparator.comparingInt(a -> a[0])); + for (int i = 0; i < sortedIntervals.length - 1; i++) { + int currentEnd = sortedIntervals[i][1]; + int nextStart = sortedIntervals[i + 1][0]; + if (nextStart < currentEnd) { + return false; + } + } + return true; + } +} +``` + +### Approach 2. Priority Queue(Heap) を使った方法 + +時間計算量: O(n log n) +空間計算量: O(n) + +- https://github.com/goto-untrapped/Arai60/pull/60/files?diff=unified&w=0#diff-b9d4ab739b4c1ab8035480d9417c186addd4d06b0f1fd82d5ecaa373998694c9R109-R125 +- Sort を優先度キュー(最小ヒープ)を使って行う +- 最も早く始まる会議から順に取り出して比較する +- 前の会議の終了時間が次の会議の開始時間よりも遅い場合(重複がある場合)、false を返す + +```java +class Solution { + public boolean canAttendMeetings(int[][] intervals) { + PriorityQueue intervalHeap = new PriorityQueue<>( + Comparator.comparingInt(a -> a[0]) + ); + for (int[] interval : intervals) { + intervalHeap.offer(interval); + } + + int[] prevMeeting = intervalHeap.poll(); + while (!intervalHeap.isEmpty()) { + int[] currentMeeting = intervalHeap.poll(); + if (prevMeeting[1] > currentMeeting[0]) { + return false; + } + prevMeeting = currentMeeting; + } + return true; + } +} +``` + +### Approach 3. 出席時刻を刻んで他の会議と突合する方法 + +時間計算量: O(n \* m) - 会議数 × 会議の時間の長さ +空間計算量: O(n \* m) + +- https://github.com/shining-ai/leetcode/pull/55/files#diff-e4aecb29a1e99485619ccf14730156b6e561b761159773644fde2a6000c54c6bR2-R11 +- https://github.com/goto-untrapped/Arai60/pull/60/files?diff=unified&w=0#diff-b9d4ab739b4c1ab8035480d9417c186addd4d06b0f1fd82d5ecaa373998694c9R49-R63 +- 会議の経過時間を start から end まで increment しながら刻んでいき Set に保存 +- 同時に Set から取り出し被りがあった時点で false を返す +- 感想 + - 実用的ではないが、こういう方法もあると参考のかと参考になった +```java +class Solution { + public boolean canAttendMeetings(int[][] intervals) { + HashSet attendTimes = new HashSet<>(); + for (int[] interval : intervals) { + for (int i = interval[0]; i < interval[1]; i++) { + if (attendTimes.contains(i)) { + return false; + } + attendTimes.add(i); + } + } + return true; + } +} ``` ## Step 3 @@ -47,5 +131,18 @@ class Solution { アクセプトされたら消すを 3 回連続できたら問題は OK。 ```java - +class Solution { + public boolean canAttendMeetings(int[][] intervals) { + int[][] sortedIntervals = Arrays.copyOf(intervals, intervals.length); + Arrays.sort(sortedIntervals, Comparator.comparingInt(a -> a[0])); + for (int i = 0; i < sortedIntervals.length - 1; i++) { + int currentEnd = sortedIntervals[i][1]; + int nextStart = sortedIntervals[i + 1][0]; + if (nextStart < currentEnd) { + return false; + } + } + return true; + } +} ``` From 72dcfd647f9a67148fe8f4f38eb51438b74eb49c Mon Sep 17 00:00:00 2001 From: Yusuke Katsuki Date: Sat, 19 Apr 2025 18:05:08 -0400 Subject: [PATCH 4/5] Add coordinate compression solution --- 0252_Meeting_Rooms/solution_ja.md | 67 +++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/0252_Meeting_Rooms/solution_ja.md b/0252_Meeting_Rooms/solution_ja.md index 9a38f54..9f16b43 100644 --- a/0252_Meeting_Rooms/solution_ja.md +++ b/0252_Meeting_Rooms/solution_ja.md @@ -125,6 +125,73 @@ class Solution { } ``` +### Approach 4 座標圧縮、差分配列+累積和を使う方法 + +- https://github.com/katsukii/leetcode/pull/20/files#r2051496046 + - > 座標圧縮と組み合わせると、increment の回数が減らせます。 +- Approach 3 へのこのコメントを受けて調べてみた + +- 会議の開始を+1, 終了を-1 として差分配列に記録。最後に累積和を走査する +- これにより同時開催中の会議数がわかる + +#### 座標圧縮(Coordinate Compression)とは + +- 任意の配列の大きさの順序を保ったまま、その値を小さくする(圧縮する) +- 例えば、以下のように与えられた数列を大小関係だけを抽出する場合: + - 入力: 1 10 5 32 99 8 10 + - 出力: 0 3 1 4 5 2 3 +- 値の範囲を小さくすることで、その後の処理にかかる時間を短縮できる場合に使用する +- 入力 → 出力 となるように Map(Dictionary)を使って管理する + +#### 差分配列(Difference Array)とは + +- ある元の配列の「隣り合う要素の差分」をとって別の配列として保持し、それを使って区間加算や累積和による高速な更新・取得を可能にするというのが一般的な定義らしい +- ここでは、開始: +1, 終了: -1 のマーカーをタイムポイント同士の差分(= 進行中の会議数)として管理 + +```java +class Solution { + public boolean canAttendMeetings(int[][] intervals) { + // 1. Collect all times + List times = new ArrayList<>(); + for (int[] interval : intervals) { + times.add(interval[0]); // Start + times.add(interval[1]); // End + } + + // 2. Remove duplicates and sort + Set uniqueTimes = new TreeSet<>(times); + List sortedTimes = new ArrayList<>(uniqueTimes); + + // 3. Cordinate compression + Map compressedTimes = new HashMap<>(); + for (int i = 0; i < sortedTimes.size(); i++) { + compressedTimes.put(sortedTimes.get(i), i); + } + + // 4. Difference array + int[] diff = new int[sortedTimes.size() + 1]; + + // 5. Set +1 / -1 + for (int[] interval : intervals) { + int start = compressedTimes.get(interval[0]); + int end = compressedTimes.get(interval[1]); + diff[start] += 1; + diff[end] -= 1; + } + + // 6. Check prefix sum, which means ongoing meetings. + int ongoing = 0; + for (int i = 0; i < sortedTimes.size(); i++) { + ongoing += diff[i]; + if (ongoing > 1) { + return false; + } + } + return true; + } +} +``` + ## Step 3 今度は、時間を測りながら、もう一回書く。 From fa30f0fe2ecf181e3f1714019768315163d38a4e Mon Sep 17 00:00:00 2001 From: Yusuke Katsuki Date: Sat, 19 Apr 2025 18:05:19 -0400 Subject: [PATCH 5/5] Add coordinate compression solution --- 0252_Meeting_Rooms/solution_ja.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/0252_Meeting_Rooms/solution_ja.md b/0252_Meeting_Rooms/solution_ja.md index 9f16b43..075f767 100644 --- a/0252_Meeting_Rooms/solution_ja.md +++ b/0252_Meeting_Rooms/solution_ja.md @@ -146,7 +146,7 @@ class Solution { #### 差分配列(Difference Array)とは - ある元の配列の「隣り合う要素の差分」をとって別の配列として保持し、それを使って区間加算や累積和による高速な更新・取得を可能にするというのが一般的な定義らしい -- ここでは、開始: +1, 終了: -1 のマーカーをタイムポイント同士の差分(= 進行中の会議数)として管理 +- ここでは、開始: +1, 終了: -1 のマーカーをタイムポイント同士の差分(= 進行中の会議数)として管理する配列が該当 ```java class Solution {