Skip to content

Conversation

aoshi2025s
Copy link
Owner

Comment on lines +110 to +111
int i = 0;
int j = 0;

Choose a reason for hiding this comment

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

1文字命名は、やるならスコープが数行のときだけにした方が良いと思います。

Copy link
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます。ここで宣言するなら、index1, index2とかですかね?

Copy link

@Hurukawa2121 Hurukawa2121 Jan 1, 2025

Choose a reason for hiding this comment

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

そうですね。
私もindex1, index2で良いと思います。

Copy link

Choose a reason for hiding this comment

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

私は、個人的には i, j 許容派ですが、たしかにループちょっと長いですね。
nums1, nums2 の添字として使われていることが

        while (i < nums1.size() && j < nums2.size()) {

この行で確定していて、このループの範囲内でしか使われていないので個人的にはあまり違和感がないのだと思います。
index1, index2 もいいんですが、長い変数名の1文字の差は見分けにくいんですよね。
i1, i2 でも私は許容です。

Copy link

Choose a reason for hiding this comment

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

要するに、わりと趣味の範囲です。


- 解法2
`set_intersection`というものがある</br>https://cpprefjp.github.io/reference/algorithm/set_intersection.html</br>
他の方が使っていた`back_inserter`が全然知らない概念のものだったので理解が難しかった</br>

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.

説明お願いします!

Copy link

@Hurukawa2121 Hurukawa2121 Dec 31, 2024

Choose a reason for hiding this comment

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

https://en.cppreference.com/w/cpp/algorithm/set_intersection

今回は std::set_intersectionOutputIt (最後の引数) に std::back_inserter を渡したかったのですね。
OutputItstd::back_inserter に分けて説明します。

OutputIt

イテレータとは「コンテナ内での要素の位置を指すもの」です。(ポインタに近いです。)
そして、OutputIt とは「操作の結果を格納する先のイテレータ」です。
(厳密には、出力イテレータという「参照への代入とインクリメントだけできるイテレータ」です。)
例えば以下のような処理が走ると、「 unique_nums1unique_nums2 で一致する要素見つけた!その要素を『格納先のイテレータ』に代入しよう」的なことが起こります。

std::set_intersection(
    unique_nums1.begin(), unique_nums1.end(),
    unique_nums2.begin(), unique_nums2.end(),
    格納先のイテレータ
);

std::back_inserter

back_inserter() は「引数のコンテナに push_back() した場合に追加される要素のイテレータ」を返します。
(つまり、引数のコンテナの新たな末尾を指すイテレータを返します。)
このイテレータに値が代入されると、コンテナの push_back() が呼び出され、イテレータは最新の末尾を指すように調整されます。

結論

まとめると、std::set_intersectionOutputItstd::back_inserter を渡すことで、 操作結果が引数のコンテナの末尾に順に追加されます。
以下の処理が走ると「 unique_nums1unique_nums2 で一致する要素見つけた!その要素を intersected_nums の末尾に追加しよう」的なことが起こります。

std::set_intersection(
    unique_nums1.begin(), unique_nums1.end(),
    unique_nums2.begin(), unique_nums2.end(),
    std::back_inserter(intersected_nums)
);

Copy link
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます!
set_intersectionを呼んだ時のback_inserterの動きがイメージできました。

@@ -0,0 +1,155 @@
# Step 1

- nums1をunordered_setに登録して重複をなくしていく
Copy link

Choose a reason for hiding this comment

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

set と unordered_set のどちらを使うかについては、以下のドキュメントを一読されることをお勧めいたします。
https://chromium.googlesource.com/chromium/src/+/HEAD/base/containers/README.md

Copy link
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます。
元々は挿入、検索、削除の操作においてsetはO(logN)でunordered_setはO(1)だから後者を使おう、という程度で認識していました。
パフォーマンス面においてunordered_setの方が大幅に優れているということはなく、メモリのオーバーヘッドもあるため、基本的にはsetやmapを使った方がいい、と理解しました。
ただ提示いただいたドキュメントは難しく感じ、きちんと理解できたとは思えませんでした。
その一つの理由としては赤黒木やハッシュテーブルの実装方法への理解がちゃんとできていないからだと思ったので、勉強してみようと思います。

Copy link

Choose a reason for hiding this comment

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

こういうのを読むのは最終ゴールなので、このコースが終わったときに読めるようになっているようにしたい、そのためにはどうしたらいいのかくらいの感覚で、解いていけばいいと思います。

public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> unique_nums1(nums1.begin(), nums1.end());
vector<int> intersected_nums;

Choose a reason for hiding this comment

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

ここでのintersectは自動詞ではないですか?
https://dictionary.cambridge.org/dictionary/english/intersect

[ I ] mathematics specialized
If sets (= groups of things with particular characteristics) intersect, they have some of the same members:

# step 3
nums1のサイズをN, nums2のサイズをKとするとき
- 時間計算量: O(N + K)
- 空間計算量: O(N + K)

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.

そもそもstep3のやり方だと空間計算量はO(N)かもしれないです(unique_nums1のサイズに比例するので)

もっと小さく抑えるならば、step2の解法3のやり方で、nums1とnums2をソートした上で一つずつ比較していくやり方であればO(1)になると思いました。(step2の解法3の計算量の見積もりがそもそも間違っていた(?))

```

# step 3
nums1のサイズをN, nums2のサイズをKとするとき

Choose a reason for hiding this comment

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

普通はMとNとかアルファベット上で連続する文字を使いませんか?

Copy link
Owner Author

Choose a reason for hiding this comment

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

確かに、片方がNならもう片方はMが自然だと他の方のコードを見て感じました

vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
int exist_nums2[1001] = {};
vector<int> ans;
unordered_set<int> nums1_set;
Copy link

Choose a reason for hiding this comment

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

好みの問題かもですがsetの変数に_setという接尾辞は不要かなと思います。
num1_setだと、変数の用途が読み取れないので、用途に合わせた名前付けをするとわかりやすくなります。

public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
int exist_nums2[1001] = {};
vector<int> ans;
Copy link

Choose a reason for hiding this comment

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

この変数は最後のfor文まで未使用で、宣言と利用までの距離が長いです。
距離が長いということは、その変数の存在をしばらく覚えていないといけなくて、記憶リソースを圧迫します。
利用の直前で宣言すると記憶を圧迫せずにすんでコードを読む際の負荷が減ります。

README.md Outdated
127. <span style="color:red">Word Ladder</span>
Copy link

Choose a reason for hiding this comment

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

コードとは関係なく、PRの差分という観点ですが、不要なdiffが入り込んでしまっているようなので、この手の差分は消せるとよさそうです。

Copy link
Owner Author

Choose a reason for hiding this comment

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

READMEに関する差分は意図しないものだったのでgithub上で修正して消したいと思ったのですが、そもそもなんで差分として表示されているのかも分かりません。
こういう場合の対処法を教えていただきたいです。

Copy link

Choose a reason for hiding this comment

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

git checkoutで特定ファイルを特定時点まで戻すとか、git resetで丸ごとコミット履歴を巻き戻したりするといけそうですね。


## 解法3
nums1のサイズをN, nums2のサイズをKとするとき</br>
- 時間計算量: O(min(N, K) + Nlog(N) + Klong(K))
Copy link

Choose a reason for hiding this comment

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

全部の流れを書き出したい意図でこう書いているのなら不要な指摘ですが、
N < N log(N), K < K log(K)なので、時間計算量はO(N log(N) + K log(K))でいいかと思います。

This reverts commit a3e8568.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants