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
123 changes: 123 additions & 0 deletions 349. Intersection of Two Arrays/IntersectionOfTwoArrays.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# step1 何も見ずに解く

## 解答
- Javaの標準ライブラリの機能で変換や積集合を取得することができるはずと思ったらやっぱりあった
- stream APIを多用しているがこれくらいだったら違和感なく読めるか?
- `addAll()`する中身をHashSetのコンストラクタに直接指定できるが、ちょっと長くて読みにくい気もする
```java
import java.util.*;

class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
Set<Integer> intersection = new HashSet<>();
intersection.addAll(Arrays.stream(nums1).boxed().toList());
intersection.retainAll(Arrays.stream(nums2).boxed().toList());
return intersection.stream().mapToInt(Integer::intValue).toArray();
}
}
Copy link

Choose a reason for hiding this comment

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

Set<Integer> set = Arrays.stream(nums1).boxed().collect(Collectors.toSet());
return Arrays.stream(nums2).filter(set::contains).distinct().toArray();

とかですかね。まあ、ループを素朴に回したほうが読みやすい気がします。

Copy link
Owner Author

Choose a reason for hiding this comment

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

StreamでSetに加工することもできましたね。
私も素朴にループを回した方が読みやすい気がします。。。

```
- Setを使わず、`List`と`distinct`でも書ける
```java
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
List<Integer> intersection = new ArrayList<>(Arrays.stream(nums1).distinct().boxed().toList());
intersection.retainAll(Arrays.stream(nums2).boxed().toList());
return intersection.stream().mapToInt(Integer::intValue).toArray();
Copy link

Choose a reason for hiding this comment

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

行数は少ないですが、一行の情報量が多いので読みづらいですね。

Copy link
Owner Author

Choose a reason for hiding this comment

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

そうですね。行数が増えても素朴にループを回す方が短時間で理解しやすいコードになる気がします。
コメントありがとうございます!

}
}
```
- 素朴に書いてみる
```java
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
// nums1のsetを作る
Set<Integer> nums1Set = new HashSet<>();
for (int num1 : nums1) {
nums1Set.add(num1);
}

List<Integer> intersection = new ArrayList<>();
for (int num2 : nums2) {
if (nums1Set.contains(num2)) {
intersection.add(num2);
nums1Set.remove(num2);
}
}

// Listの中身を配列に変換
int[] result = new int[intersection.size()];
for (int i = 0; i < intersection.size(); i++) {
result[i] = intersection.get(i);
}
return result;
}
}
```
# step2 他の方の解答を見る
- 入力として渡される配列の長さをチェックして、短い方をSetにするという視点は抜けていた
- `if (nums1.length < nums2.length) intersection(nums2, nums1);`みたいな書き方はシンプルでいいなと思った
- 入力がソートされていた場合などのケースについては考えれていなかった
## 解答
- https://github.com/nanae772/leetcode-arai60/pull/14/files
- 入力が両方ともソートされていた場合
- 先頭から見ていって、一致していれば結果に含める
- 最初に重複排除せずintersectionをSetで書くのもあり
- あるいはwhileループ中の条件を少し工夫するのもあり
```java
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
int[] uniqueNums1 = Arrays.stream(nums1).distinct().toArray();
int[] uniqueNums2 = Arrays.stream(nums2).distinct().toArray();
Arrays.sort(uniqueNums1);
Arrays.sort(uniqueNums2);
Comment on lines +69 to +72
Copy link

Choose a reason for hiding this comment

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

以下のように一行で書いてもよいかなと思いました

Suggested change
int[] uniqueNums1 = Arrays.stream(nums1).distinct().toArray();
int[] uniqueNums2 = Arrays.stream(nums2).distinct().toArray();
Arrays.sort(uniqueNums1);
Arrays.sort(uniqueNums2);
int[] uniqueNums1 = Arrays.stream(nums1).sorted().distinct().toArray();
int[] uniqueNums2 = Arrays.stream(nums2).sorted().distinct().toArray();

Copy link
Owner Author

Choose a reason for hiding this comment

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

ご提案いただいた書き方の方がスマートですね。
distinct()があるくらいならsorted()もあるはずと書きながら気づくべきでした。
ありがとうございます!


List<Integer> intersection = new ArrayList<>();
int i = 0;
int j = 0;
while (i < uniqueNums1.length || j < uniqueNums2.length) {
Copy link

Choose a reason for hiding this comment

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

こちら&&にしないと配列外参照でエラーになりました

Suggested change
while (i < uniqueNums1.length || j < uniqueNums2.length) {
while (i < uniqueNums1.length && j < uniqueNums2.length) {

Copy link
Owner Author

Choose a reason for hiding this comment

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

失礼しました。仰る通り&&が正解です。
お恥ずかしい限りです。

if (uniqueNums1[i] == uniqueNums2[j]) {
intersection.add(uniqueNums1[i]);
i ++;
Copy link

Choose a reason for hiding this comment

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

Javaにあまり詳しくないのですが、インクリメント演算子と変数の間にスペースを空けるのは一般的なのでしょうか?

Copy link
Owner Author

Choose a reason for hiding this comment

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

一般的ではないですね。。。
自分でも何故スペースを入れたのか分からないです。
ありがとうございます。

j ++;
continue;
}
if (uniqueNums1[i] < uniqueNums2[j]) {
i ++;
} else {
j ++;
}
}
return intersection.stream().mapToInt(Integer::intValue).toArray();
}
}
```
- https://github.com/akmhmgc/arai60/pull/10/files
- 片方の配列がソートされていれば二分探索でも書ける
```java
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
Arrays.sort(nums1);
Set<Integer> intersection = new HashSet<>();
for (int num : nums2) {
int intersectionIndex = Arrays.binarySearch(nums1, num);
if (intersectionIndex >= 0) {
intersection.add(nums1[intersectionIndex]);
}
}
return intersection.stream().mapToInt(Integer::intValue).toArray();
}
}
```
# step3 3回ミスなく書く
- IDEによる補完が無いと書けないStream APIの練習も兼ねてStream APIで書く
## 解答
```java
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
Set<Integer> intersection = new HashSet<>();
intersection.addAll(Arrays.stream(nums1).boxed().toList());
intersection.retainALl(Arrays.stream(nums2).boxed().toList());
return intersection.stream().mapToInt(Integer::intValue).toArray();
}
}
```