[LeetCode解題攻略] 49. Group Anagrams

更新於 發佈於 閱讀時間約 6 分鐘

題目描述

給定一個字串陣列 strs,請將字母相同但排列順序不同的單字(即異位詞,Anagrams)分組。可以以任意順序返回結果

範例

範例 1

輸入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
輸出: [["bat"], ["nat", "tan"], ["ate", "eat", "tea"]]

範例 2

輸入: strs = [""]
輸出: [[""]]

範例 3

輸入: strs = ["a"]
輸出: [["a"]]

限制條件

  • 1 ≤ strs.length ≤ 10^4
  • 0 ≤ strs[i].length ≤ 100
  • strs[i] 只包含小寫英文字母

解題思路

異位詞(Anagrams)是指由相同字母組成,但字母排列順序不同的單字。因此,所有異位詞的特徵就是它們的字母組合相同

解法的核心思路是:

  • 找出相同特徵的字串,並將它們歸類到同一組。
  • 這裡的「特徵」可以使用:
    1. 排序後的字串("eat" → "aet")
    2. 字母計數(頻率表)("eat" → {e:1, a:1, t:1})

解法一:排序字串作為 Key(Hash Table)

思路:

  1. 對每個字串進行排序,異位詞排序後會變成相同的字串
  2. 使用雜湊表(defaultdict)存儲這些異位詞,Key 為排序後的字串,Value 為原始字串的列表。
  3. 回傳雜湊表的所有值

程式碼:

from collections import defaultdict
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
anagrams = defaultdict(list)

for s in strs:
sorted_str = "".join(sorted(s)) # 排序字母後轉回字串
anagrams[sorted_str].append(s) # 加入對應的群組

return list(anagrams.values()) # 取出所有群組

時間與空間複雜度分析

  • 時間複雜度:O(n⋅klog⁡k)
    • 其中 n 為 strs 的長度,k 為字串平均長度。
    • 每個字串排序需要 O(klog⁡k) 時間,因此總共為 O(n⋅klog⁡k)。
  • 空間複雜度:O(n⋅k)
    • 哈希表存儲了 n 個字串,每個字串長度為 k,因此為 O(n⋅k)。

解法二:字母頻率計數作為 Key(Hash Table)

思路:

  1. 使用字母頻率計數來當作 Key,而非排序字串。
  2. 每個字串可以轉換為一個 tuple(長度 26,代表 a~z 的出現次數)。
  3. 相同的頻率分布代表相同的異位詞,用雜湊表存儲這些群組。

程式碼:

from collections import defaultdict
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
anagrams = defaultdict(list)

for s in strs:
count = [0] * 26 # 建立 26 個字母頻率陣列
for char in s:
count[ord(char) - ord('a')] += 1 # 計算每個字母出現次數
anagrams[tuple(count)].append(s) # 轉換為 tuple 作為 key

return list(anagrams.values()) # 取出所有群組

時間與空間複雜度分析

  • 時間複雜度:O(n⋅k)
    • 計算每個字串的字母頻率需要 O(k) 時間,總共 O(n⋅k)。
    • 比解法一更快,因為不需要排序(省去 O(klog⁡k))。
  • 空間複雜度:O(n⋅k)
    • 需要存儲 n 個字串,且 tuple(count) 佔用 O(26),所以為 O(n⋅k)。

解法三:使用 Counter(Python 內建函式)

Python 的 collections.Counter 可以直接計算字母頻率,類似於解法二。


程式碼:

from collections import defaultdict, Counter
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
anagrams = defaultdict(list)

for s in strs:
anagrams[frozenset(Counter(s).items())].append(s) # 使用 frozenset 作為 key

return list(anagrams.values())

時間與空間複雜度分析

  • 時間複雜度:O(n⋅k)
    • Counter(s) 需要 O(k),總共 O(n⋅k)。
  • 空間複雜度:O(n⋅k)
    • Counter(s).items() 轉換為 frozenset 佔用額外空間。

結論

  • 如果你想要簡單易懂的方式,推薦解法一(排序字串作為 Key)。
  • 如果你想提高效率,推薦解法二(字母頻率計數作為 Key),因為避免了排序 O(klog⁡k) 的開銷。
  • 如果你想用 Python 內建函式,解法三(Counter)也是不錯的選擇。

這題使用了雜湊表與字串處理,熟悉後可以應用在很多字串相關的題目上!


歡迎來到我的部落格!這裡記錄了軟體工程師的日常生活點滴,並分享程式設計與演算法的實用教學。無論你是初學者還是有經驗的開發者,都能在這裡找到深入淺出的技術解析與實戰技巧。此外,我也會分享工作中的心路歷程與學習心得,讓你不僅學到技術,更能瞭解軟體開發的實際應用與挑戰。希望透過這個平台,能與你共同成長,激發對技術的熱情!
留言
avatar-img
留言分享你的想法!
給定一個 n × n 的 2D 矩陣 matrix,將其順時針旋轉 90 度(原地 旋轉,不使用額外的矩陣)。
給定一個可包含重複數字的整數數組 nums,返回所有不重複的排列。
給定一個不含重複數字的整數陣列 nums,返回所有可能的排列。
給定一個非負整數陣列 nums,其中每個元素代表你在該位置最多可以跳躍的步數,目標是從陣列的第一個位置跳到最後一個位置。請找出你所需要的最小跳躍次數。
給定一個輸入字串 s 和一個Pattern p,要求實現一個能夠支援字元* 和 ?的Wildcard Pattern Matching的函式。
給定兩個非負整數的字串 num1 和 num2,分別表示兩個數字。要求模擬乘法運算,並返回結果字串,不能使用內建的大數處理函式(例如 Python 的 int 或 BigInteger)。
給定一個 n × n 的 2D 矩陣 matrix,將其順時針旋轉 90 度(原地 旋轉,不使用額外的矩陣)。
給定一個可包含重複數字的整數數組 nums,返回所有不重複的排列。
給定一個不含重複數字的整數陣列 nums,返回所有可能的排列。
給定一個非負整數陣列 nums,其中每個元素代表你在該位置最多可以跳躍的步數,目標是從陣列的第一個位置跳到最後一個位置。請找出你所需要的最小跳躍次數。
給定一個輸入字串 s 和一個Pattern p,要求實現一個能夠支援字元* 和 ?的Wildcard Pattern Matching的函式。
給定兩個非負整數的字串 num1 和 num2,分別表示兩個數字。要求模擬乘法運算,並返回結果字串,不能使用內建的大數處理函式(例如 Python 的 int 或 BigInteger)。
你可能也想看
Google News 追蹤
Thumbnail
全新 vocus 挑戰活動「方格人氣王」來啦~四大挑戰任你選,留言 / 愛心 / 瀏覽數大 PK,還有新手專屬挑戰!無論你是 vocus 上活躍創作者或剛加入的新手,都有機會被更多人看見,獲得站上版位曝光&豐富獎勵!🏆
Thumbnail
本文探討AI筆記工具的優缺點、選擇建議及未來趨勢,比較NotebookLM、OneNote+Copilot、Notion AI、Obsidian+GPT插件和Palantir Foundry等工具,並強調安全注意事項及個人需求評估的重要性。
Thumbnail
全方位分析脫離繼承戰的方法,大膽猜測誰會成為卡丁國下一任國王。
Thumbnail
給定一個字串陣列,請把它們所共有的字元伴隨著出現次數輸出。這篇文章介紹如何使用字典統計出現次數,和字典取交集的方法來解決此問題。並提供了複雜度分析和關鍵知識點。
Thumbnail
Leetcode 精選75題 題目與題解 熱門考點 目錄 (持續更新中) 建議從左側目錄 或者 按Ctrl+F輸入關鍵字進行搜尋
Thumbnail
題目會給定一個陣列nums和一個目標值goal。計算子陣列總和=goal的數目有多少。演算法包含前綴和和字典的技巧,時間複雜度為O(n),空間複雜度為O(n)。
Thumbnail
題目敘述 題目會給定我們兩個字串。 第一個是指定順序的字串order。 第二個是輸入字串s。 要求我們依據order給定的順序,重新排列s。 如果出現order中沒有出現的字母,任意位置皆可。 合法答案可能不只一組,輸出其中一種即可。 題目的原文敘述 測試範例 Example
Thumbnail
題目敘述 題目會給我們一個字串s。 要求我們移除字串中的星號,還有刪除星號左手邊最靠近的第一個字元。 以字串的形式返回輸出答案。 題目的原文敘述 測試範例 Example 1: Input: s = "leet**cod*e" Output: "lecoe" Explanation:
Thumbnail
題目敘述 題目會給定一個輸入字串s和一套編碼規則,要求我們針對字串s進行解碼,並且以字串的形式返回答案。 編碼規則: 數字[字串] -> []內的字串以對應倍數做展開,而且允許巢狀編碼。 例如: 3[a] 解碼完就是 aaa 2[bc] 解碼完就是 bcbc 2[a2[b]] = 2
Thumbnail
題目敘述 題目會給定我們兩個整數陣列作為輸入nums1, nums2,要求我們找出兩個陣列的差異值。 找出在nums1但是不在nums2的元素,以陣列的形式放在answer[0]輸出。 找出在nums2但是不在nums1的元素,以陣列的形式放在answer[1]輸出。 題目的原文敘述
Thumbnail
題目敘述 題目會給定我們兩個輸入字串word1, word2,要求我們依照word1,word2,word1,word2, ... 交叉前進的方式,合併兩個字串,作為輸出。 題目的原文敘述 測試範例 Example 1: Input: word1 = "abc", word2 = "pq
Thumbnail
題目敘述 題目會給定我們兩個字串word1 和 word2。 允許我們不限制次數進行下列兩種操作: 任意調換其中兩個字元的位置。 把字串中的某個字元全部置換成另一個字元,同時把另一個字元同時置換成某個字元。(例如把字串中原本的a都換成b,把原本的b都換成a) 問我們能不能通過上述兩項操作,
Thumbnail
題目敘述 題目會給我們兩個字串作為輸入,分別是字串s和字串t,問我最少要做幾次字元轉換,讓字串t和字串s成為Anagram"同字母異序詞"? 註: 例如 god 和 dog 就是 Anagram 同字母異序詞,也是就說,組成字母相同,但是順序可以重新排列。 題目的原文敘述 測試範例 Ex
Thumbnail
全新 vocus 挑戰活動「方格人氣王」來啦~四大挑戰任你選,留言 / 愛心 / 瀏覽數大 PK,還有新手專屬挑戰!無論你是 vocus 上活躍創作者或剛加入的新手,都有機會被更多人看見,獲得站上版位曝光&豐富獎勵!🏆
Thumbnail
本文探討AI筆記工具的優缺點、選擇建議及未來趨勢,比較NotebookLM、OneNote+Copilot、Notion AI、Obsidian+GPT插件和Palantir Foundry等工具,並強調安全注意事項及個人需求評估的重要性。
Thumbnail
全方位分析脫離繼承戰的方法,大膽猜測誰會成為卡丁國下一任國王。
Thumbnail
給定一個字串陣列,請把它們所共有的字元伴隨著出現次數輸出。這篇文章介紹如何使用字典統計出現次數,和字典取交集的方法來解決此問題。並提供了複雜度分析和關鍵知識點。
Thumbnail
Leetcode 精選75題 題目與題解 熱門考點 目錄 (持續更新中) 建議從左側目錄 或者 按Ctrl+F輸入關鍵字進行搜尋
Thumbnail
題目會給定一個陣列nums和一個目標值goal。計算子陣列總和=goal的數目有多少。演算法包含前綴和和字典的技巧,時間複雜度為O(n),空間複雜度為O(n)。
Thumbnail
題目敘述 題目會給定我們兩個字串。 第一個是指定順序的字串order。 第二個是輸入字串s。 要求我們依據order給定的順序,重新排列s。 如果出現order中沒有出現的字母,任意位置皆可。 合法答案可能不只一組,輸出其中一種即可。 題目的原文敘述 測試範例 Example
Thumbnail
題目敘述 題目會給我們一個字串s。 要求我們移除字串中的星號,還有刪除星號左手邊最靠近的第一個字元。 以字串的形式返回輸出答案。 題目的原文敘述 測試範例 Example 1: Input: s = "leet**cod*e" Output: "lecoe" Explanation:
Thumbnail
題目敘述 題目會給定一個輸入字串s和一套編碼規則,要求我們針對字串s進行解碼,並且以字串的形式返回答案。 編碼規則: 數字[字串] -> []內的字串以對應倍數做展開,而且允許巢狀編碼。 例如: 3[a] 解碼完就是 aaa 2[bc] 解碼完就是 bcbc 2[a2[b]] = 2
Thumbnail
題目敘述 題目會給定我們兩個整數陣列作為輸入nums1, nums2,要求我們找出兩個陣列的差異值。 找出在nums1但是不在nums2的元素,以陣列的形式放在answer[0]輸出。 找出在nums2但是不在nums1的元素,以陣列的形式放在answer[1]輸出。 題目的原文敘述
Thumbnail
題目敘述 題目會給定我們兩個輸入字串word1, word2,要求我們依照word1,word2,word1,word2, ... 交叉前進的方式,合併兩個字串,作為輸出。 題目的原文敘述 測試範例 Example 1: Input: word1 = "abc", word2 = "pq
Thumbnail
題目敘述 題目會給定我們兩個字串word1 和 word2。 允許我們不限制次數進行下列兩種操作: 任意調換其中兩個字元的位置。 把字串中的某個字元全部置換成另一個字元,同時把另一個字元同時置換成某個字元。(例如把字串中原本的a都換成b,把原本的b都換成a) 問我們能不能通過上述兩項操作,
Thumbnail
題目敘述 題目會給我們兩個字串作為輸入,分別是字串s和字串t,問我最少要做幾次字元轉換,讓字串t和字串s成為Anagram"同字母異序詞"? 註: 例如 god 和 dog 就是 Anagram 同字母異序詞,也是就說,組成字母相同,但是順序可以重新排列。 題目的原文敘述 測試範例 Ex