diff --git a/49/49.md b/49/49.md new file mode 100644 index 0000000..6edb31a --- /dev/null +++ b/49/49.md @@ -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))としている方もいた。 +個人的には本当にどっちでも良い気がしたのですが、皆さんの感覚としてはどうでしょうか。 + +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) + 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で書かれたネイティブコードで走ってそう?なのでそこそこ早いかなと思ったのだが、ハッシュの計算がボトルネックになっているのだろうか? +というか、むしろ普通にfor文で回したほうがCounterを使うより早かった。。。(38ms程度になった) + +```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()) +``` + +ネイティブコードで走っていればいいというものでもないのか、そもそもネイティブコードで走っていないのか・・・詳しい方ご教示ください。 + +## 最終コード(エラーを出さずに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()) +```