Back to Blog
5 min read
1.2k views
Group Anagrams 是 Valid Anagram(EP.02)的進階版。上一題只需要判斷兩個字串是不是 anagram,這一題要把一組字串裡所有 anagram 分到同一組。解這題需要同時理解「如何找出 anagram 的共同特徵」和「Python 的 defaultdict 怎麼用」。
題目理解
Input / Output
關鍵問題:如何讓 anagram 有相同的 key?
Anagram 的本質:相同的字母,不同的排列順序。所以如果把每個字排序,所有 anagram 排序後都會得到一樣的字串。
排序作為 key 的概念
⚠️ 為什麼不用 str 而用 tuple?
用
sorted("eat") 回傳的是 list(['a', 'e', 't']),而 list 不能當 dict 的 key(list 是可變的,不能 hash)。用
tuple(sorted(s)) 轉成 tuple,就可以當 key 了。defaultdict:不用再寫 if key not in dict
普通 dict 存取不存在的 key 會拋 KeyError。每次要新增一個 key 都要先判斷它存不存在:
普通 dict — 需要手動初始化
defaultdict 讓你指定「當 key 不存在時,自動建立什麼預設值」,省掉那個 if 判斷:
defaultdict — 自動初始化
✅
常見用法:
defaultdict(list) 的意思是:傳入 list 這個函式。當存取不存在的 key 時,自動呼叫 list() 建立空 list。常見用法:
defaultdict(list)、defaultdict(int)(預設 0)、defaultdict(set)(預設空 set)完整解法
1
建立 defaultdict(list),key 是排序後的 tuple
每個 anagram 群組共享一個 key
2
遍歷所有字串,計算 key 並分組
tuple(sorted(s)) 當 key,把字串 append 到對應的 list3
回傳 dict 的所有 values
每個 value 就是一個 anagram 群組
Group Anagrams — 完整解法
⏱ Time: O(n · k log k) n=字串數量, k=平均字串長度💾 Space: O(n · k)
逐步追蹤執行過程
用範例 ["eat","tea","tan","ate","nat","bat"] 走一遍:
執行追蹤
進階解法:用字母頻率當 key
排序需要 O(k log k),但其實可以用「26 個字母的頻率陣列」當 key,降到 O(k):
字母頻率 key — O(n·k)
ord(c) - ord('a') 是把字母轉成 0-25 的 index 的慣用技巧。
ord('a') = 97,ord('z') = 122,相減就是字母在字母表中的位置。Group Anagrams 的精髓不是演算法,而是「找到一個能代表整個群組的 key」。這種把問題轉換成 key 設計問題的思維,在後面的 Sliding Window 和 Two Pointers 也會一直出現。
本篇重點整理
🔑Anagram 的共同 key = tuple(sorted(s)),排序後相同就是同組
📦defaultdict(list) — key 不存在時自動建立空 list,省掉 if 判斷
⚠️list 不能當 dict key(可變、不能 hash),要先轉 tuple
🚀進階:26個字母頻率陣列當 key,可從 O(k log k) 降到 O(k)
上一篇
EP.02 — Set vs Dict
選對資料結構,解題事半功倍
下一篇
EP.04 — Two Pointers
即將推出
LeetCode
HashMap
defaultdict
Sorting
Python
EP.03