Skip to content
Open
Show file tree
Hide file tree
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
65 changes: 65 additions & 0 deletions 349.Intersection of Two Arrays/349.Intersection of Two Arrays
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#STEP1 何も見ずに解く
2重ループ(2ポインタ法)で解こうとしたが時間が切れてしまった。
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

時間が切れてしまったというのは Time Limited Exceeded と判定されたということでしょうか?それともソースコードを書きあげるまでの時間が長くなりすぎてしまったということでしょうか?

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.

レビューありがとうございます。
ここに時間が切れてしまったと記載しているのは、後者の意味になります。
この問題に取り組んだ際、やり方を勘違いしていて、5分考えてわからなかったらそこで
STEP1が終了→STEP2に進むものだと思っており、上記のような書き方をしました。

先日コーディング練習会参加マニュアルを読み直した際、
「標準的な進め方」に、5分考えてわからなければ答えを見て正解になるところまでが第一段階とありましたので、
今取り組んでいる387ではそのように進めているところです。


#STEP2 解答を見てコードを整える
https://github.com/yas-2023/leetcode_arai60/pull/13/commits/b813f57848ba38b03617bf7c1094cd558a6a2b57
・入力値の状態によってベストな方法が異なる
両方の配列をsetにしてretainAllする→setを2つ作るので
両方の配列が同じくらいの長さの場合→短い方の配列をsetにして、長い方の配列をループしながらlook upする
片方の配列が極端に長い場合(未ソート)→2ポインタ法
片方の配列が極端に長い場合(ソート済み)→2分探索法

https://github.com/kt-from-j/leetcode/pull/10/commits/8aca48aa93a922d2b46e41f47ab0278ead43a93b
streamを使って短く書く方法もある。
streamは書きなれておらず、forループの練習としてstreamを使わずに書く。

#調べたこと
Set→重複なしのコレクション
https://docs.oracle.com/en/java/javase/25/docs/api//java.base/java/util/Set.html

一つ一つ調べながら全部の解法をjavaで書いてみようとしていたが、
構文エラーや知らない・忘れている所を調べていて時間がかかっていたので、まずは一つだけ実装してみることにする。
Setの練習として、短い方の配列をsetにして、長い方の配列をループしながらlook upする方法で解く。
時間計算量:O(n1 + n2) Set構築 + long_numsのループ
空間計算量:O(min(n1, n2)) 短い方の配列でSet構築

#STEP3解答

```java

class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
Set<Integer> short_nums = new HashSet<>();
int[] long_nums;

if (nums1.length > nums2.length) {
for (int num2 : nums2) {
short_nums.add(num2);
}
long_nums = nums1;
}
else {
for (int num1 : nums1) {
short_nums.add(num1);
}
long_nums = nums2;
}

List<Integer> intersection = new ArrayList<>();
for (int long_num : long_nums) {
if (short_nums.contains(long_num)) {
intersection.add(long_num);
short_nums.remove(long_num);
}
}
int[] result = new int[intersection.size()];
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

return intersection.stream()
    .mapToInt(Integer::intValue)
    .toArray();

という書き方もできそうです。

for (int i = 0; i < intersection.size(); i++) {
result[i] = intersection.get(i);
}

return result;

}
}

```
62 changes: 62 additions & 0 deletions 349.Intersection of Two Arrays/STEP3.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#STEP1 何も見ずに解く
2重ループで解こうとしたが時間が切れてしまった。

#STEP2 解答を見てコードを整える
https://github.com/yas-2023/leetcode_arai60/pull/13/commits/b813f57848ba38b03617bf7c1094cd558a6a2b57
・入力値の状態によってベストな方法が異なる
両方の配列をsetにしてretainAllする→setを2つ作るので計算量が増える。
両方の配列が同じくらいの長さの場合→短い方の配列をsetにして、長い方の配列をループしながらlook upする
片方の配列が極端に長い場合(未ソート)→2ポインタ法
片方の配列が極端に長い場合(ソート済み)→2分探索法

https://github.com/kt-from-j/leetcode/pull/10/commits/8aca48aa93a922d2b46e41f47ab0278ead43a93b
streamを使って短く書く方法もある。
streamは書きなれておらず、まずはforループの練習としてstreamを使わずに書く。
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

こういうの書いてみるの良いですね。


■調べたこと
Set→重複なしのコレクション
https://docs.oracle.com/en/java/javase/25/docs/api//java.base/java/util/Set.html

一つ一つ調べながら全部の解法をjavaで書いてみようとしていたが、
構文エラーや知らない・忘れている所を調べていて時間がかかっていたので、まずは一つだけ実装してみることにする。
Setの練習として、短い方の配列をsetにして、長い方の配列をループしながらlook upする方法で解く。
時間計算量:O(n1 + n2) Set構築 + long_numsのループ
空間計算量:O(min(n1, n2)) Set構築

#STEP2、3解答
```java
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
Set<Integer> short_nums = new HashSet<>();
int[] long_nums;

if (nums1.length > nums2.length) {
for (int num2 : nums2) {
short_nums.add(num2);
}
long_nums = nums1;
Comment on lines +35 to +37
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Javaの変数名はsnake_caseよりcamelCaseの方が一般的だと思います。
short_nums -> shourtNums

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.

言語によって、一般的とされる命名規則が違うのですね。
勉強になりました。
今回はもともとpythonのコードを参考にしたので、そのままsnake_caseで書いていたのですが、
次はJavaでより一般的なcamelCaseで書くようにしたいと思います。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

参考までにスタイルガイドへのリンクを共有いたします。

https://google.github.io/styleguide/javaguide.html#s5.2.7-local-variable-names

Local variable names are written in lowerCamelCase.

なお、このスタイルガイドは“唯一の正解”というわけではなく、数あるガイドラインの一つに過ぎません。チームによって重視される書き方や慣習も異なります。そのため、ご自身の中に基準を持ちつつも、最終的にはチームの一般的な書き方に合わせることをお勧めします。

}
else {
for (int num1 : nums1) {
short_nums.add(num1);
}
long_nums = nums2;
}
Comment on lines +31 to +44
Copy link
Copy Markdown

@naoto-iwase naoto-iwase Nov 25, 2025

Choose a reason for hiding this comment

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

テクニカルなんですが、下記のように書く方法もあります。

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        if (nums1.length > nums2.length) {
            return intersection(nums2, nums1);
        }
        
        // 以降はnums1.length <= nums2.lengthとして考えれば良い
        Set<Integer> set = new HashSet<>();
        for (int num : nums1) {
            set.add(num);
        }

        List<Integer> intersection = new ArrayList<>();
        // 以下は同様
    }
}

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.

再帰的にintersectionを呼び出すことで
必ずnums1.length <= nums2.lengthとなり、
short_numsとlong_numsを場合分けして設定する必要がなくなるということですかね。
こんな方法があるとは考えもつかなかったです。
とてもテクニカルなので、今は適切に使いこなせるか自信がないですが、
方法の一つとして頭に入れておこうと思います。


List<Integer> intersection = new ArrayList<>();
for (int long_num : long_nums) {
if (short_nums.contains(long_num)) {
intersection.add(long_num);
short_nums.remove(long_num);
}
Comment on lines +48 to +51
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ガード節というテクニックでネストを浅くできるので選択肢としてあると良いと思いました。元々のコードのネストが深くないので過剰かもしれません。

Suggested change
if (short_nums.contains(long_num)) {
intersection.add(long_num);
short_nums.remove(long_num);
}
if (!short_nums.contains(long_num)) {
continue;
}
intersection.add(long_num);
short_nums.remove(long_num);

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.

返信遅くなり失礼いたしました。
レビューありがとうございます。
ガード節について調べてみたのですが、処理対象外を先にはじいてから処理を行うやり方なんですね。
勉強になりました。
ネストが浅くなることで可読性やメンテナンス性が上がるなどのメリットがあるとのことで、今後コードを書くときに取り入れようと思います。

}
int[] result = new int[intersection.size()];
for (int i = 0; i < intersection.size(); i++) {
result[i] = intersection.get(i);
}

return result;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

return のあとに空行を入れるのはあまり見ないように思います。

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.

あまり見ないとのこと、承知しました。
特に大きな意味はなく、手癖で改行をしていたのですが、
専門家から見た場合、おそらくノイズになってしまうのかもしれないと思料いたしました。
returnの後には改行をいれない方向で次回以降取り組もうと思います。
エンジニアとしての一般的な感覚がまだ身についていないので、
このような、教科書を読むだけではわからない暗黙的な常識についても身に着けていきたく思います。
(勉強不足で、暗黙的でなければ、すみません。)

}
}
```