From 38080cd605e0b2c7edbcd38a799a40c6dd58832d Mon Sep 17 00:00:00 2001 From: Masakuni Date: Sun, 11 Jan 2026 12:56:10 +0900 Subject: [PATCH 1/3] step1 --- problems/49.group-anagrams/memo.md | 12 ++++++++++++ problems/49.group-anagrams/step1.py | 21 +++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 problems/49.group-anagrams/memo.md create mode 100644 problems/49.group-anagrams/step1.py diff --git a/problems/49.group-anagrams/memo.md b/problems/49.group-anagrams/memo.md new file mode 100644 index 0000000..1afc862 --- /dev/null +++ b/problems/49.group-anagrams/memo.md @@ -0,0 +1,12 @@ +## step1 +- 全ての組み合わせを列挙してその中の一部とすると、strs[i].length <= 100で100!ほどの計算量が必要になり不可なはず +- 出てきた、文言をアルファベット順に並び替えたものをkeyとして保管しておくといけそう + - 出てきた文言の並び替えO(MlogM)*文言の個数NでNMlogM = 10^2 * 7 * 10^4 = 7 * 10^6 + - pythonは1秒で10^8計算できるとする70msくらいでいけそう + - pythonで文字列をsortした後にlistに1文字ずつ入るのを知らなかった + - joinでまた文字列に戻した + +## step2 + +## step3 + diff --git a/problems/49.group-anagrams/step1.py b/problems/49.group-anagrams/step1.py new file mode 100644 index 0000000..aee055a --- /dev/null +++ b/problems/49.group-anagrams/step1.py @@ -0,0 +1,21 @@ +# +# @lc app=leetcode id=49 lang=python3 +# +# [49] Group Anagrams +# + +# @lc code=start +class Solution: + def groupAnagrams(self, strs: List[str]) -> List[List[str]]: + sorted_to_str = {} + for str in strs: + sorted_str = "".join(sorted(str)) + if sorted_str in sorted_to_str: + sorted_to_str[sorted_str].append(str) + else: + sorted_to_str[sorted_str] = [str] + + return [value for value in sorted_to_str.values()] + + +# @lc code=end From 993a4b1908182777b22af47371f8f793dff28039 Mon Sep 17 00:00:00 2001 From: Masakuni Date: Sun, 11 Jan 2026 15:15:37 +0900 Subject: [PATCH 2/3] step2 --- problems/49.group-anagrams/memo.md | 35 +++++++++++++++++++++++++++++ problems/49.group-anagrams/step2.py | 21 +++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 problems/49.group-anagrams/step2.py diff --git a/problems/49.group-anagrams/memo.md b/problems/49.group-anagrams/memo.md index 1afc862..4f695ab 100644 --- a/problems/49.group-anagrams/memo.md +++ b/problems/49.group-anagrams/memo.md @@ -7,6 +7,41 @@ - joinでまた文字列に戻した ## step2 +- 流石に出てきた文言の並び替え無しでは解けないと思うのでこれ以上の高速化は無理だと思う +- `sorted_to_str`よりも良い変数名(`sorted_to_元々/最初の順序のような単語`)が無いか考えたが元々の引数でstrsとなっていたのでstrとした +- 空文字列が入ってきた場合は今回は問題でOKとなっているが、実際のケースでは使われ方によって変わってくるだろうなと思った +- 他の人のコードを見る +- https://github.com/Hiroto-Iizuka/coding_practice/pull/12/files + - 確かにカウンターでよかった + - `時間計算量は確かにO(nk) vs O(nk log k)でカウンターの方が有利ですが、カウンターの方は文字列にアルファベットの小文字しか来ないことを前提としており、文字種の拡張性に欠けます。また、kはnに比べたら小さく、sorted(str)もstr.join()もネイティブコードで動くので割と速いので実行時間で見たらおそらく大きな問題(差)にはならず、可読性や拡張性の観点からも私ならソートする方法を採用すると思います。なお重要なのはどちらを選ぶかよりも、こうした多角的な観点で比較検討できるかどうかだと思います。` + - カウンターの選択肢をもった上で考えたかった + - 最後は`list(sorted_to_str.values())`でよかった +- https://github.com/mamo3gr/arai60/pull/12/files + - `ソートにする。時間計算量は単語数が支配的だろうから、ヒストグラムを作るのがソートよりも速くても、その寄与は小さいことが予想される。空間計算量のオーダーは変わらない(たぶんソートの場合の法が多少有利)。コードの簡潔さはソートの方が有利そうで、ここが個人的に大きい(ヒストグラムをタプルで作って…みたいなのが面倒)。`こんな風な選択肢をもった上での意思決定をしたかった + - `frozenset`というものがあるみたい。普通のsetと異なり、削除ができないが辞書のkeyに使えるものらしい + - defaultdictの方が分岐が一つ減って良かった + - keyをtupleにする方法もあった + - 選択肢としてもっておきたい + - `chrは本来組み込み関数chr()の名前なので、変数名として使うのは避けたほうが良いように思います。ch or c でいかがでしょうか?` + - 関数があることを知らなかった。組み込み関数は数がそんなに多くなさそうなので全部目を通しておく + - https://docs.python.org/ja/3/library/functions.html +- https://github.com/naoto-iwase/leetcode/pull/12/files + - `NUM_CHARACTERS = len(string.ascii_lowercase)`の書き方はとても良かったので使う時は思い出したい + - 予約後はできるだけ変数名にしない(https://github.com/naoto-iwase/leetcode/pull/12/files#r2415311731) + - なのでstrもやめる +``` +FORBIDDEN = { + # 他言語(C/C++/Java/TS/Go/Python)での予約語になりがち + "char","int","long","short","float","double","bool","string", + "class","struct","union","enum","interface","implements","extends", + "public","private","protected","package","import","export","module", + "new","delete","this","super","const","var","let","yield","lambda", + "async","await","from","in","is","not","or","and","record","match","type", + # Python 組み込み + "list","dict","set","tuple","id","sum","max","min","any","all","input", + "bytes","map","filter","range","str","type" +} +``` ## step3 diff --git a/problems/49.group-anagrams/step2.py b/problems/49.group-anagrams/step2.py new file mode 100644 index 0000000..a3606d3 --- /dev/null +++ b/problems/49.group-anagrams/step2.py @@ -0,0 +1,21 @@ +# +# @lc app=leetcode id=49 lang=python3 +# +# [49] Group Anagrams +# + +# @lc code=start +import collections + + +class Solution: + def groupAnagrams(self, strs: List[str]) -> List[List[str]]: + sorted_to_word = collections.defaultdict(list) + for word in strs: + sorted_word = "".join(sorted(word)) + sorted_to_word[sorted_word].append(word) + + return [sorted_to_word.values()] + + +# @lc code=end From cbbb94b3a352cfeb2e56b38b122f31d6d715dcd4 Mon Sep 17 00:00:00 2001 From: Masakuni Date: Sun, 11 Jan 2026 15:21:35 +0900 Subject: [PATCH 3/3] step3 --- problems/49.group-anagrams/memo.md | 2 ++ problems/49.group-anagrams/step3.py | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 problems/49.group-anagrams/step3.py diff --git a/problems/49.group-anagrams/memo.md b/problems/49.group-anagrams/memo.md index 4f695ab..653b9ca 100644 --- a/problems/49.group-anagrams/memo.md +++ b/problems/49.group-anagrams/memo.md @@ -44,4 +44,6 @@ FORBIDDEN = { } ``` ## step3 +- `sorted_to_word`はvalueがリストなのでwordsとする(どこかの指摘コメントであったのを書いてる途中で思い出した) +- 実装は短いのとロジックも単純なのですんなり書けた diff --git a/problems/49.group-anagrams/step3.py b/problems/49.group-anagrams/step3.py new file mode 100644 index 0000000..0ce3d12 --- /dev/null +++ b/problems/49.group-anagrams/step3.py @@ -0,0 +1,22 @@ +# +# @lc app=leetcode id=49 lang=python3 +# +# [49] Group Anagrams +# + +# @lc code=start +import collections + + +class Solution: + def groupAnagrams(self, strs: List[str]) -> List[List[str]]: + sorted_to_words = collections.defaultdict(list) + + for word in strs: + sorted_word = "".join(sorted(word)) + sorted_to_words[sorted_word].append(word) + + return list(sorted_to_words.values()) + + +# @lc code=end