Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 10

Grouping and Classification with Hash Maps

Recommended resources

Welcome to our next lesson on hash map patterns. In our previous sessions, we explored how to use hash maps for frequency counting and for the "complement lookup" pattern, which is central to solving problems like Two Sum. Today, we will master a third fundamental pattern: grouping and classification.

This pattern is your go-to tool when a problem asks you to categorize items based on a shared, intrinsic property. Our goal is to solve such problems by devising a "canonical key" for each group and using a hash map to efficiently collect all items that belong together. We'll focus on the classic "Group Anagrams" problem, a favorite in technical interviews that perfectly illustrates this powerful technique.

The Grouping Pattern: From Raw Data to Classified Buckets

Imagine you're given a jumble of items and asked to sort them into labeled bins. The core challenge is figuring out what the label for each bin should be. In algorithmic terms, this "label" is a canonical representation—a unique signature that is identical for all items belonging to the same group, but different for items in other groups.

Once you have a method for generating this signature, a hash map becomes the perfect tool. You can use the signature as the key and a list of items as the value.

Let's make this concrete with our main problem for today: Group Anagrams (LeetCode #49).

The task is to take a list of strings and group the anagrams together. For example, given ["eat", "tea", "tan", "ate", "nat", "bat"], the desired output is [["eat", "ate", "tea"], ["tan", "nat"], ["bat"]].

This image shows how a list of strings is partitioned into groups where each group contains words that are anagrams of each other.

This image shows how a list of strings is partitioned into groups where each group contains words that are anagrams of each other.

The fundamental question is: what is the unique signature of an anagram group?


Approach 1: Sorting as the Canonical Key

Two words are anagrams if they are made of the same characters with the same frequencies. A simple yet powerful insight is that if you sort the characters of two anagrams, the resulting strings will be identical.

  • "eat" sorted is "aet"
  • "tea" sorted is "aet"
  • "tan" sorted is "ant"

This sorted string is a perfect canonical key. We can iterate through our input list, sort each string to generate its key, and then use a hash map to group the original strings by these keys.

This technique is a prime example of the "Grouping / Bucketing" pattern.

Hash Map Patterns for Coding Interviews: The Essential Guide ...

This article from AlgoArk introduces several key hash map patterns. We'll focus on the one relevant to our current problem.

In the section "5 Essential Hash Map Patterns", read the definition of Pattern 3 — Grouping / Bucketing. This formally describes the strategy we are about to implement.

Let's see how to translate this idea into code. The following video provides a clear, step-by-step walkthrough of the implementation, paying close attention to a crucial Python-specific detail.

Group Anagrams - LeetCode 49 - Python

This video by Deepti Talesra details the sorting-based approach.

First, watch the explanation of the core logic, which involves using a sorted version of a word as a key in a dictionary to group anagrams. Next, pay close attention to the segment on a key Python implementation detail. The sorted() function returns a list, which is mutable and cannot be a dictionary key. The video explains why and how to convert this list into an immutable type (in this case, a string) before using it as a key.

Complexity Analysis of the Sorting Approach

Let be the number of strings in the input list, and be the maximum length of any string.

  • Time Complexity: . We iterate through each of the strings. For each string, we sort its characters, which takes time.
  • Space Complexity: . In the worst case, every string is unique, and we store all strings in our hash map, which collectively contain characters.

This is a very respectable solution that you can confidently present in an interview. However, a sharp interviewer might ask, "Can you do better?"


Approach 2: Character Counts for Optimization

The bottleneck in our first approach is sorting, which costs . Can we generate our canonical key more quickly? Yes, by using a character count.

Another way to define anagrams is that they have identical character counts. For example, "eat" and "tea" both have one 'a', one 'e', and one 't'. We can represent this count as an array of 26 integers (one for each letter of the alphabet). This array becomes our new canonical key.

Generating this key takes only time, as we just need a single pass through the string to count the characters. This is a significant improvement over , especially for long strings.

The NeetCode video below provides a concise explanation of this more optimal approach.

Group Anagrams - Categorize Strings by Count - Leetcode 49

This video walks through the more efficient character-counting method.

First, watch the explanation of the high-level concept. Understand why using a character count array is more efficient than sorting and how it leads to an overall time complexity of O(N \cdot K). Then, follow the Python implementation. The video explains how to map characters to array indices using their ASCII values (ord()) and, crucially, why the final count list must be converted into a tuple to be used as a dictionary key in Python.

Here is the complete, optimized Python code for this approach. This is the kind of clean, efficient solution that top companies look for.

from collections import defaultdict

def group_anagrams(strs: list[str]) -> list[list[str]]:
    """
    Groups anagrams together using a character count as the canonical key.
    Time: O(N * K), Space: O(N * K)
    N is the number of strings, K is the max length of a string.
    """
    groups = defaultdict(list)
    
    for s in strs:
        # Create a fixed-size array to store character counts.
        count = [0] * 26
        
        for char in s:
            # Map each character to an index (0-25) and increment its count.
            count[ord(char) - ord('a')] += 1
            
        # A list is mutable and cannot be a dict key, so convert to a tuple.
        groups[tuple(count)].append(s)
        
    return list(groups.values())

# Example Usage:
strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
print(group_anagrams(strs))
# Output: [['eat', 'tea', 'ate'], ['tan', 'nat'], ['bat']]

The Interview Context

Knowing both solutions is excellent, but demonstrating strong problem-solving and communication skills is what will set you apart in an interview. This involves starting with a solid approach, analyzing it, and then discussing potential optimizations.

Let's examine a real mock interview transcript to see how this plays out.

Python Interview with a Facebook Engineer (Group Anagrams)

This transcript from interviewing.io captures a candidate solving this exact problem. It's a fantastic resource for understanding what interviewers look for.

First, observe how the candidate proposes the sorting approach as their initial plan. This is a great strategy: start with a correct, clear solution. Later in the discussion, the candidate correctly identifies sorting as the bottleneck and suggests an optimization: using a character counter. They also astutely recognize the need for an immutable key (a tuple), showing deep language knowledge. Finally, read the interviewer's feedback on the complexity analysis. This is a crucial takeaway for your own interviews: always be precise by defining your variables (e.g., N for the number of strings, K for the maximum string length).


Conclusion

You have now added the grouping and classification pattern to your hash map toolkit. This pattern is incredibly versatile and appears in many forms. The core skill is always the same: identifying a property that can be transformed into a canonical key.

Key Takeaways:

  • Grouping Pattern: To group items, devise a canonical key that is the same for all items in a group. Use this key in a hash map where the values are lists of the original items.
  • Canonical Keys for Anagrams: The two primary canonical keys for anagrams are the sorted string ( to generate) and the character count array ( to generate).
  • Immutability is Key: In Python, dictionary keys must be immutable. This often requires converting mutable types like lists into tuples or strings before using them as keys.
  • Interview Strategy: Start with a correct solution (like sorting), analyze its complexity, and then discuss optimizations (like character counting). Clearly articulate the trade-offs.

In our next lesson, we'll pivot from hash maps to focus on another fundamental data structure: the array. We will explore powerful in-place manipulation techniques that are essential for solving problems with strict memory constraints.