← Back to All Algorithms

Medium Interview Frequency: ⭐⭐⭐⭐

Group Anagrams

Group strings that are anagrams of each other. Return groups in any order.

Hash Map String Signatures

📚 Table of Contents

  1. Problem Statement
  2. Real-World Analogy
  3. Key Insights
  4. Solution Approaches
  5. Step-by-Step Walkthrough
  6. Complexity Analysis
  7. Edge Cases
  8. Test Cases
  9. Interview Tips
  10. Related Problems
  11. Key Takeaways

📋 Problem Statement

Given an array of strings, cluster words that share identical character counts. Words in same cluster are anagrams.

Examples

Example 1:
Input: ["eat","tea","tan","ate","nat","bat"]
Output: [["eat","tea","ate"],["tan","nat"],["bat"]]
Example 2:
Input: [""]
Output: [[""]]

Constraints

🎯 Real-World Analogy

Sorting Keys for Lockers

Two keys belong in same locker if they have exactly the same tooth pattern, even if teeth appear in different order when drawn as strings.

Build a canonical signature per word, and use that signature as locker ID.

💡 Key Insights

💻 Solution Approaches

Approach 1: Sorted-String Signature

Time: O(N * K log K) | Space: O(N * K)

Simple and readable. Sort each word to get canonical key.

Approach 2: Frequency Signature (Recommended)

Time: O(N * K) | Space: O(N * K)

Build 26-length count vector per word and use it as map key.

Python Implementation

from collections import defaultdict from typing import List def group_anagrams(strs: List[str]) -> List[List[str]]: groups = defaultdict(list) for word in strs: counts = [0] * 26 for ch in word: counts[ord(ch) - ord('a')] += 1 key = tuple(counts) groups[key].append(word) return list(groups.values())

JavaScript Implementation

function groupAnagrams(strs) { const groups = new Map(); for (const word of strs) { const counts = new Array(26).fill(0); for (const ch of word) { counts[ch.charCodeAt(0) - 97] += 1; } const key = counts.join("#"); if (!groups.has(key)) { groups.set(key, []); } groups.get(key).push(word); } return Array.from(groups.values()); }

🔍 Step-by-Step Walkthrough

Trace ["eat","tea","tan","ate","nat","bat"]:

"eat" -> signature for a,e,t -> group 1 starts.
"tea" and "ate" produce same signature -> append to group 1.
"tan" and "nat" share another signature -> group 2.
"bat" unique signature -> group 3. Return all groups.

⚡ Complexity Analysis

Time Complexity: O(N * K)

Space Complexity: O(N * K)

🔧 Edge Cases

🧪 Test Cases

Python

def normalize(groups): return sorted(sorted(g) for g in groups) def test_group_anagrams(): out1 = group_anagrams(["eat","tea","tan","ate","nat","bat"]) assert normalize(out1) == normalize([["eat","tea","ate"],["tan","nat"],["bat"]]) assert group_anagrams([""]) == [[""]] assert group_anagrams(["a"]) == [["a"]] out4 = group_anagrams(["ab","ba","ab"]) assert normalize(out4) == normalize([["ab","ba","ab"]]) print("✅ all tests passed")

JavaScript

function testGroupAnagrams() { const out = groupAnagrams(["eat","tea","tan","ate","nat","bat"]); console.assert(out.length === 3, "test 1"); console.assert(JSON.stringify(groupAnagrams([""])) === JSON.stringify([[""]]), "test 2"); console.assert(JSON.stringify(groupAnagrams(["a"])) === JSON.stringify([["a"]]), "test 3"); console.log("✅ all tests passed"); }

💼 Interview Tips

🎓 Key Takeaways

← Back to All Algorithms