-
Notifications
You must be signed in to change notification settings - Fork 0
49. Group Anagrams #12
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| ## 何も見ずに溶いてみる | ||
|
|
||
| ソートを使った解法で解いた。 | ||
| 最初sorted(string)を直接キーにしようとしたが、ミュータブルなのでエラーが出てしまった。一度文字列にしてキーとした。 | ||
|
|
||
| ```python | ||
| class Solution: | ||
| def groupAnagrams(self, strs: List[str]) -> List[List[str]]: | ||
| sorted_to_strings = defaultdict(list) | ||
| for string in strs: | ||
| sorted_ = "".join(sorted(string)) | ||
| sorted_to_strings[sorted_].append(string) | ||
| return list(sorted_to_strings.values()) | ||
| ``` | ||
|
|
||
| ## いろいろ調べてみる | ||
|
|
||
| https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/edit?tab=t.0#heading=h.e5dwa7yj3tv0 | ||
| https://github.com/Fuminiton/LeetCode/pull/12/files それぞれのアルファベットの出現回数をリストで管理している | ||
| https://github.com/azriel1rf/leetcode-prep/pull/4/files | ||
| https://github.com/kazukiii/leetcode/pull/13/files frozensetを使っている方法 | ||
| https://github.com/hayashi-ay/leetcode/pull/19/files | ||
| https://qiita.com/amber__dev/items/542cd6389a8c423f7dae | ||
|
|
||
| ひとまず十分そうな解法を思いついたらとりあえず実装に取り掛かってしまう癖があるのはよくないかもしれない。 | ||
| 次の問題からは発想を一つ思いついても他の手段を発想する時間を多少取るようにしてみよう。 | ||
|
|
||
| 自分のコードでいう"".join(sorted(string))の部分をtuple(sorted(string))としている方もいた。 | ||
| 個人的には本当にどっちでも良い気がしたのですが、皆さんの感覚としてはどうでしょうか。 | ||
|
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. アナグラムなので str の方が自然かもと思いますが、好みだと思われます。 |
||
|
|
||
| frozensetを使った方法は | ||
| - 英小文字以外を含むすべての文字に対応している | ||
| - sortする方法と違い1つのstringあたりの計算量が文字列長をLとしてO(L)で済み、かつ同じ文字列が何度も登場するような入力でもメモリ消費が必要以上に増加しない | ||
| という点で良いなと思ったので、こちらのコードも作ってみた。 | ||
|
|
||
| ```python | ||
| class Solution: | ||
| def groupAnagrams(self, strs: List[str]) -> List[List[str]]: | ||
| group_to_strings = defaultdict(list) | ||
| for s in strs: | ||
| counter = Counter(s) | ||
|
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. 何のカウンターかわかるとより読みやすいと思います。 |
||
| group = frozenset(counter.items()) | ||
| group_to_strings[group].append(s) | ||
| return list(group_to_strings.values()) | ||
| ``` | ||
|
|
||
| しかし、このコードでsubmitするとだいぶ時間がかかることに気づいた。上のsortを用いた解放は7msぐらいでできるのに対し、こちらは50msぐらいかかる。 | ||
|
|
||
| https://github.com/python/cpython/blob/main/Lib/collections/__init__.py#L546 | ||
| ここを見る限りcounterの処理はCで書かれたネイティブコードで走ってそう?なのでそこそこ早いかなと思ったのだが、ハッシュの計算がボトルネックになっているのだろうか? | ||
|
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. 下につけたのは適当に拾ってきたソートの速度の比較ですが、ネイティブコードにすると10-20倍くらいは簡単に変わるんですね。 C 言語と Python は50-100倍くらい違い、ただしネイティブコードでもガーベージコレクションなど Python Object の操作をしないといけないので、C 言語並までにはならないだろうくらいの推測です。 文字列のハッシュ計算のほうが(タプルなどよりも構造が単純なので)なんとなく速そうですね。 https://medium.com/@tuvo1106/how-fast-can-you-sort-9f75d27cf9c1#7d4f 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. 意図がちょっとはっきりしなかったんですが、速度が 7 ms か 50 ms かと7倍くらいの話をしていますが、これは同一アルゴリズムでも最適化で変わる範囲なので、インタープリターであることに理由を求める必要はないと思います、(これくらいの差は環境にもよるので色々実験しないといえることはあまりない)ということです。
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. なるほど、、ありがとうございます。 |
||
| というか、むしろ普通にfor文で回したほうがCounterを使うより早かった。。。(38ms程度になった) | ||
|
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. leetcode上の実行時間は目安程度と過去にコメントされてました。正確には計測するコードを書いた方が良さそうです。メモリ消費の観点ではどうなったかも気になりました。ですが実際には多目的最適化で、比較的コードの複雑さが優先されるとのことです。 |
||
|
|
||
| ```python | ||
| class Solution: | ||
| def groupAnagrams(self, strs: List[str]) -> List[List[str]]: | ||
| group_to_strings = defaultdict(list) | ||
| for s in strs: | ||
| counter = defaultdict(int) | ||
| for c in s: | ||
| counter[c] += 1 | ||
| group = frozenset(counter.items()) | ||
| group_to_strings[group].append(s) | ||
| return list(group_to_strings.values()) | ||
| ``` | ||
|
|
||
| ネイティブコードで走っていればいいというものでもないのか、そもそもネイティブコードで走っていないのか・・・詳しい方ご教示ください。 | ||
|
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. sortedもネイティブコード化されているので,コンパイル済みかどうかはあまり関係ないかもしれないです. |
||
|
|
||
| ## 最終コード(エラーを出さずに3回書いてみる) | ||
|
|
||
| ```python | ||
| class Solution: | ||
| def groupAnagrams(self, strs: List[str]) -> List[List[str]]: | ||
| group_to_strings = defaultdict(list) | ||
| for s in strs: | ||
| group = "".join(sorted(s)) | ||
| group_to_strings[group].append(s) | ||
| return list(group_to_strings.values()) | ||
| ``` | ||
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.
markdownをプレビューした時に改行が入っていないようです。行末に半角スペース2つ入れると改行されて見やすくなると思います。
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.
あ、本当ですね。ありがとうございます。