Accounts Merge#108
Conversation
|
|
||
| name_to_indexes = {} | ||
| for i, account in enumerate(accounts): | ||
| name_to_indexes.setdefault(account[0], []).append(i) |
There was a problem hiding this comment.
同一の名前で異なるユーザーがいるにもかかわらず、同一のエントリーに追加している点に違和感を感じました。
There was a problem hiding this comment.
見返して、このファイルのロジック自体が冗長だと思いました。
(このstep1.pyはLeetCode上で解くことだけを目的に書いたコードです。UnionFindを用いた改善をstep2_union_find.pyに書き、レビューを受けてその改善をstep2_union_find_revised.pyに行いました。)
| [accounts[indexes[0]][0]] + sorted(set(accounts[indexes[0]][1:])) | ||
| ] | ||
|
|
||
| mail_to_rank = {} |
There was a problem hiding this comment.
rank が何を指しているのか分かりにくく感じました。これは indexes 内のインデックスでしょうか。より分かりやすい名前を付けるか、ロジック自体をシンプルにしたほうが良いと思いました。
| account_union_find.union(r, mail_to_rank[email]) | ||
| else: | ||
| mail_to_rank[email] = r | ||
| rank_to_index = {r: i for r, i in enumerate(indexes)} |
There was a problem hiding this comment.
これはそのまま indexes を使えばよいように思いました。 accounts[rank_to_index[r]][1:] は accounts[indexes[r]][1:] となると思います。
There was a problem hiding this comment.
その通りで、rank_to_indexの作成自体不要ですね
|
|
||
| name_to_indexes = {} | ||
| for i, account in enumerate(accounts): | ||
| name_to_indexes.setdefault(account[0], []).append(i) |
There was a problem hiding this comment.
defaultdict を使用したほうがシンプルになると思いました。
https://docs.python.org/ja/3.6/library/collections.html#collections.defaultdict
| email_to_neighbor.setdefault(hub, []).append(email) | ||
| email_to_neighbor.setdefault(email, []).append(hub) | ||
|
|
||
| accounts_merged = [] |
| def accountsMerge(self, accounts: List[List[str]]) -> List[List[str]]: | ||
| email_to_name = {} | ||
| email_to_neighbor = {} | ||
| hubs = [] |
There was a problem hiding this comment.
hubs を定義せず、 email_to_name または email_to_neighbor のキーで traverse() を回したほうがシンプルになると思いました。
There was a problem hiding this comment.
たしかに余計な変数でした。採用させていただきました。
| std::vector<int> parent; | ||
| std::vector<int> size; | ||
|
|
||
| UnionFind(int n) { |
There was a problem hiding this comment.
UnionFind(int n) : parent(n), size(n, 1) {としたほうが良いかもしれません。詳しくは Effective C++ 第 3 版 第1章4項「オブジェクトは、使う前に初期化しよう」をご覧ください。
https://www.maruzen-publishing.co.jp/book/b10111861.html
There was a problem hiding this comment.
C++でメンバ変数は関数本体に入る前に初期化されるので、元のコードではデフォルトの状態でメンバ変数が作成された後、後からサイズや値が代入されることになっていた。
初期化子リストを使うと、無駄な空のインスタンス作成をスキップして、最初から必要な形でメモリを確保して作成される、ということですね。
紹介していただいた本は時々練習会で見かけるので気になっています。余裕ができたら手に取ってみようと思います。
| } | ||
| } | ||
|
|
||
| for (auto& [root, emails] : root_to_emails) { |
There was a problem hiding this comment.
非 const 参照で受けると、 root と emails を変更するという意図があると誤解させてしまうと思います。 const 参照で受けることをお勧めいたします。
There was a problem hiding this comment.
そのような解釈をあたえることを認識していませんでした。修正いたしました。
| std::vector<std::vector<std::string>> accountsMerge(std::vector<std::vector<std::string>>& accounts) { | ||
| UnionFind union_find(accounts.size()); | ||
| std::unordered_map<std::string, int> mail_to_account_index; | ||
| std::vector<std::vector<std::string>> accounts_merged; |
There was a problem hiding this comment.
宣言場所と使用箇所が離れていると、読み手は使用箇所まで変数を記憶しておかなければならず、読み手の短期記憶を圧迫してしまうと思います。使用箇所の直前で宣言することをお勧めいたします。
There was a problem hiding this comment.
これは一般的な話ですね。なぜこの位置に書いたのか、自分でも分からずにいます。修正しました。
https://leetcode.com/problems/accounts-merge/description/?envType=problem-list-v2&envId=rab78cw1