-
Notifications
You must be signed in to change notification settings - Fork 0
242. Valid Anagram #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
ryosuketc
wants to merge
2
commits into
main
Choose a base branch
from
242_valid_anagram
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| # 242. Valid Anagram | ||
|
|
||
| https://leetcode.com/problems/valid-anagram/ | ||
|
|
||
| ## Comments | ||
|
|
||
| ### step1 | ||
|
|
||
| * `map` と `unordered_map` | ||
| * https://cpprefjp.github.io/reference/map/map.html | ||
| * https://cpprefjp.github.io/reference/unordered_map/unordered_map.html | ||
| * `map` は binary tree、`unordered_map` は hash で実装されているらしい。 | ||
| * ああだから `map` の計算量は平均・最悪とも O(logN) で | ||
| * `unordered_map` は償却 O(1)、ただし最悪 O(N) なのか (合ってる?) | ||
| * hash strategy がイケてなくて全部衝突すると O(N) | ||
| * 全く同じことが `set` vs. `unordered_set` でも言える | ||
| * なんか最悪計算量が悪くなるの嫌だし、この辺は知識として把握したうえで、なんでもないなら `map`, `set` を使うほうが安定しているのでいい気がする…というのが私の好みではあるんだが Modern C++ における一般的な engineering practice としてはどうなんだろう。 | ||
| * `unordered_map` の例にこんなのがある | ||
| * https://cpprefjp.github.io/reference/unordered_map/unordered_map.html | ||
|
|
||
| ```cpp | ||
| std::unordered_map<std::string, int> um{ {"1st", 1}, {"2nd", 2}, {"3rd", 3}, }; | ||
| ``` | ||
| * contd. | ||
| * 前コメントもらった initializer list というやつだと思うけど、`um {...}` とスペース開けるのが普通では?違うのかな。 | ||
| * https://cpprefjp.github.io/lang/cpp11/initializer_lists.html | ||
| * C++ (だけではないと思うけど)、スペースとかインデントとか改行とか割と無頓着だよな。どっちがいいかはわからないけど。 | ||
|
|
||
| ```cpp | ||
| std::vector<int> v1 = {1, 2, 3}; | ||
| std::vector<int> v2 {1, 2, 3}; | ||
|
|
||
| ``` | ||
|
|
||
| * `at` と `[]` | ||
| * `at` は範囲外で例外を投げる。 | ||
| * `[]` は未定義動作 | ||
| * https://stackoverflow.com/questions/9376049/when-should-i-use-vectorat-instead-of-vectoroperator | ||
| * 基本的に `at` を使うほうがいいのかな? | ||
| * `map` の存在しないキーにアクセスした場合、指定された型の初期値で初期化されるらしい (`int` なら `0`、ポインタなら `nullptr` などというように) | ||
| * ローカル変数の宣言のみの場合は未定義動作になるはずだが、これはどういう違いなんだろう。 | ||
| * `find` というのもあるみたい | ||
| * https://cpprefjp.github.io/reference/map/map/find.html | ||
| * 見つからならなかったら `end()` というのを返すらしい | ||
| * `std::unordered_map::count`、そもそもキーがユニークなんだから意味ある?と思った。使い所はよくわからんけど (`mulptimap`?あたりとインターフェース揃えるためなのかな) | ||
| * `Solution` | ||
| * `map` に対する for 文をどう書くのがいいか苦闘した。 | ||
| * 他の解答も眺めて `for (const auto& [s_char, s_char_count] : s_char_to_count)` で Python の unpack みたいに書けることを知った。 | ||
| * const 参照で受けるべきか値で受けるべきかまだよくわからん | ||
| * そもそも `map` を範囲 for で回すと pair が返るっぽいので、こんな感じでアクセスする。可読性が低い気がするが慣れの問題? | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ranged for と auto の入る C++11 以前だとイテレータを型から書いていました。そういう歴史的経緯があります。 |
||
|
|
||
|
|
||
| ```cpp | ||
| for (const auto& pair : s_char_to_count) { | ||
| if (pair.second != t_char_to_count[pair.first]) { | ||
| return false; | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| * contd. | ||
| * `getCountMap` はコピーが発生する可能性を考えると書き込み先を引数でもらった方がいいのかな | ||
| * https://github.com/ryosuketc/leetcode_grind75/pull/5#discussion_r2274647457 | ||
| * *追記:* いや、参照 (かポインタ) を引数に渡せばコピーはされないのか。 | ||
|
|
||
| ### step2 | ||
|
|
||
| * このバリエーションはいくつもあって、今回は 2 つ map を使ったけどこんな感じでも解けるだろう。 | ||
| * sort して全部比べる。 | ||
| * 1 map だけ用意して、最後に全要素が `0` になっているか確認する | ||
| * https://github.com/eito2002/LeetCode/pull/2/files | ||
| * sort のやり方確認しようと思ったけど、他の要素でお腹いっぱいなのでまた今度。 | ||
| * `Solution1` | ||
| * pair をそのまま使う | ||
| * この場合、`pair` という変数名は普通なのかな | ||
| * `Solution2` | ||
| * find を使う | ||
| * この場合、`it` という変数名は普通なのかな | ||
| * C++ の場合、`pair` とか `it` みたいな、それ自体はあまり重要じゃないんだけど、みたいな中間変数的なものが発生しがちで、それには短い名前で済ませたくなる。C++ の慣習としてはありなのかな? | ||
| * `Solution3` | ||
| * getCountMap に書き込み先を渡す | ||
| * https://github.com/ryosuketc/leetcode_grind75/pull/5#discussion_r2274647457 を模倣してなんとか書いてみたけどポインタとか参照とか de-reference とか大分わけわからなくなってきた。時間をかけてゆっくり考えるとまあ意味はわかるんだけど。 | ||
|
|
||
| ### step3 | ||
|
|
||
| * step1 のやり方で、`getCountMap` だけ、`s` を参照で受け取るようにした。コピーは NRVO とか信じてなんとかならないだろうか… | ||
| * 追記: | ||
| * いや、参照 (かポインタ) を引数に渡せばコピーはされないのか。 | ||
| * 参照渡しをする、しないによるコピー (引数に渡す時のコピー) と RVO のとき問題になっているコピーを同一視してしまっていた気がする。 | ||
| * 前者は、ポインタか参照を関数の引数に渡せばよい。 | ||
| * 後者は値を返すときにコピーされる問題で、嫌なら最初から書き込み先のアドレスを渡して関数内でそこに書いていくか、あるいは (N)RVO が効くことを期待するか | ||
| * …という理解であっているかな。 | ||
|
Comment on lines
+87
to
+92
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. #3 |
||
| * (N)RVO の理解は浅い気がする | ||
| * https://cpprefjp.github.io/lang/cpp17/guaranteed_copy_elision.html | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| #include <map> | ||
|
|
||
| class Solution { | ||
| public: | ||
| bool isAnagram(string s, string t) { | ||
| if (s.size() != t.size()) { | ||
| return false; | ||
| } | ||
| std::map<char, int> s_char_to_count = getCountMap(s); | ||
| std::map<char, int> t_char_to_count = getCountMap(t); | ||
| for (const auto& [s_char, s_char_count] : s_char_to_count) { | ||
| if (s_char_count != t_char_to_count[s_char]) { | ||
| return false; | ||
| } | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| private: | ||
| std::map<char, int> getCountMap(std::string s) { | ||
| std::map<char, int> char_to_count; | ||
| for (char c : s) { | ||
| ++char_to_count[c]; | ||
| } | ||
| return char_to_count; | ||
| } | ||
|
|
||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| // pair をそのまま使う | ||
| #include <map> | ||
|
|
||
| class Solution1 { | ||
| public: | ||
| bool isAnagram(string s, string t) { | ||
| if (s.size() != t.size()) { | ||
| return false; | ||
| } | ||
| std::map<char, int> s_char_to_count = getCountMap(s); | ||
| std::map<char, int> t_char_to_count = getCountMap(t); | ||
| for (const auto& pair : s_char_to_count) { | ||
| if (pair.second != t_char_to_count[pair.first]) { | ||
| return false; | ||
| } | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| private: | ||
| std::map<char, int> getCountMap(std::string s) { | ||
| std::map<char, int> char_to_count; | ||
| for (char c : s) { | ||
| ++char_to_count[c]; | ||
| } | ||
| return char_to_count; | ||
| } | ||
|
|
||
| }; | ||
|
|
||
|
|
||
|
|
||
| // find を使う | ||
| #include <map> | ||
|
|
||
| class Solution2 { | ||
| public: | ||
| bool isAnagram(string s, string t) { | ||
| if (s.size() != t.size()) { | ||
| return false; | ||
| } | ||
| std::map<char, int> s_char_to_count = getCountMap(s); | ||
| std::map<char, int> t_char_to_count = getCountMap(t); | ||
| for (const auto& [s_char, s_count] : s_char_to_count) { | ||
| auto it = t_char_to_count.find(s_char); | ||
| if (it == t_char_to_count.end() || s_count != it->second) { | ||
| return false; | ||
| } | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| private: | ||
| std::map<char, int> getCountMap(std::string s) { | ||
| std::map<char, int> char_to_count; | ||
| for (char c : s) { | ||
| ++char_to_count[c]; | ||
| } | ||
| return char_to_count; | ||
| } | ||
|
|
||
| }; | ||
|
|
||
|
|
||
| // getCountMap に書き込み先を渡す | ||
| #include <map> | ||
|
|
||
| class Solution { | ||
| public: | ||
| bool isAnagram(string s, string t) { | ||
| if (s.size() != t.size()) { | ||
| return false; | ||
| } | ||
| std::map<char, int> s_char_to_count; | ||
| getCountMap(s, &s_char_to_count); | ||
| std::map<char, int> t_char_to_count; | ||
| getCountMap(t, &t_char_to_count); | ||
| for (const auto& [s_char, s_count] : s_char_to_count) { | ||
| auto it = t_char_to_count.find(s_char); | ||
| if (it == t_char_to_count.end() || s_count != it->second) { | ||
| return false; | ||
| } | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| private: | ||
| void getCountMap(std::string& s, std::map<char, int>* to_map) { | ||
| for (char c : s) { | ||
| ++(*to_map)[c]; | ||
| } | ||
| } | ||
|
|
||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| #include <map> | ||
|
|
||
| class Solution { | ||
| public: | ||
| bool isAnagram(string s, string t) { | ||
| if (s.size() != t.size()) { | ||
| return false; | ||
| } | ||
| std::map<char, int> s_char_to_count = getCountMap(s); | ||
| std::map<char, int> t_char_to_count = getCountMap(t); | ||
| for (const auto& [s_char, s_char_count] : s_char_to_count) { | ||
| if (s_char_count != t_char_to_count[s_char]) { | ||
| return false; | ||
| } | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| private: | ||
| std::map<char, int> getCountMap(const std::string& s) { | ||
| std::map<char, int> char_to_count; | ||
| for (char c : s) { | ||
| ++char_to_count[c]; | ||
| } | ||
| return char_to_count; | ||
| } | ||
|
|
||
| }; |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Structured binding で C++17 からで比較的新しい機能です。
なんとなくいつから入ったかは意識しておくといいかと思います。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ありがとうございます。structured binding というんですね。
https://cpprefjp.github.io/lang/cpp17/structured_bindings.html