49. Group Anagrams
MediumDescription
給定字串陣列
strs,將所有 anagram 分為一組。字串只包含小寫英文字母,回傳順序不限。
Example:
Input: strs = [“eat”,“tea”,“tan”,“ate”,“nat”,“bat”] Output: [[“bat”],[“nat”,“tan”],[“ate”,“eat”,“tea”]]
Intuition#
核心思路:找到 anagram 的「標準化表示」作為 HashMap 的 key,相同 key 的字串歸為同一組。
- 兩個字串是 anagram <=> 排序後相同 <=> 字元頻率完全相同
- 關鍵在於如何定義每個 anagram 群組的 key
Approaches#
1: Sort as Key#
- 概念: 將每個字串排序後作為 key,排序結果相同的字串是 anagram
- 時間複雜度:
O(n * k log k)- n 為字串數量,k 為最長字串長度 - 空間複雜度:
O(n * k)- 儲存所有字串
class Solution {
fun groupAnagrams(strs: Array<String>): List<List<String>> {
val map = HashMap<String, MutableList<String>>()
for (s in strs) {
val key = String(s.toCharArray().also { it.sort() })
map.getOrPut(key) { mutableListOf() }.add(s)
}
return map.values.toList()
}
}⭐2: Character Count as Key#
- 概念: 用字元頻率陣列的字串表示作為 key,例如 “eat” -> “1#0#0#…#1#…#0#1#0#…"(a=1, e=1, t=1),避免排序
- 時間複雜度:
O(n * k)- n 為字串數量,k 為最長字串長度,計數為線性 - 空間複雜度:
O(n * k)- 儲存所有字串
class Solution {
fun groupAnagrams(strs: Array<String>): List<List<String>> {
val map = HashMap<String, MutableList<String>>()
for (s in strs) {
val count = IntArray(26)
for (c in s) count[c - 'a']++
val key = count.joinToString("#")
map.getOrPut(key) { mutableListOf() }.add(s)
}
return map.values.toList()
}
}注意 key 的分隔符號:不能直接拼接數字(如 “1100…” 會產生歧義),必須用分隔符如
#來區分各字母的計數。
🔑 Takeaways#
- Pattern: 分組問題 -> 定義 canonical key + HashMap 歸類
- 關鍵技巧: 字元頻率作 key 可以將排序的 O(k log k) 降到 O(k);
getOrPut是 Kotlin 中簡潔處理 Map 預設值的慣用寫法