Skip to content

Leetcode 49 - Group Anagrams

Difficulty: medium

Table of contents

Open Table of contents

Problem

Given an array of strings strs, group the anagrams together. You can return the answer in any order.

An Anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.

Example 1:

Input: strs = ["eat","tea","tan","ate","nat","bat"]
Output: [["bat"],["nat","tan"],["ate","eat","tea"]]

Example 2:

Input: strs = [""]
Output: [[""]]

Example 3:

Input: strs = ["a"]
Output: [["a"]]

Constraints:

Explanation/Approach

The problem can be approached by categorizing anagrams using a hash table. Anagrams have the same character counts, so sorting the characters in each string can serve as a key to group them.

Hash Table and Sorting Approach:

Character Frequency as Key:

Solution: Hash Table and Sorting

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        # A dictionary to hold the sorted tuple of characters as keys and corresponding anagrams as values
        anagrams = {}

        for s in strs:
            # Sort the characters of the string to form the key
            key = tuple(sorted(s))
            # Add the original string to the corresponding list in the hash table
            if key not in anagrams:
                anagrams[key] = []
            anagrams[key].append(s)

        # Return the grouped anagrams
        return list(anagrams.values())

Time and Memory Complexity

The time complexity is O(nklogk), where n is the number of strings in strs and k is the maximum length of a string. This is due to the sorting of each string. The space complexity is O(nk), to store the hash table and the output list of anagrams.

Explanation

This solution uses sorting and hashing to group anagrams. Each string is transformed into a sorted tuple of characters, which acts as a unique identifier for its group of anagrams. The strings are then added to the corresponding lists in the hash table. Finally, the values of the hash table, which are lists of anagrams, are returned.

Visual Representation:

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

Sorted keys and corresponding anagrams:
('a', 'e', 't'): ['eat', 'tea', 'ate']
('a', 'n', 't'): ['tan', 'nat']
('a', 'b', 't'): ['bat']

Output: [['eat', 'tea', 'ate'], ['tan', 'nat'], ['bat']]

The visualization shows how each string is transformed into a sorted tuple of characters and grouped together with its anagrams in the hash table. This method effectively organizes the strings into groups of anagrams.

Solution: Hash Table with Character Count

To group anagrams without sorting each string, we can use the frequency of each character as a key. This approach involves counting the frequency of each character in a string and using the character counts as a hashable key.

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        anagrams = {}

        for s in strs:
            # Counting the frequency of each character in the string
            count = [0] * 26  # 26 for each letter in the alphabet
            for char in s:
                count[ord(char) - ord('a')] += 1

            # Using the tuple of counts as a key
            key = tuple(count)
            if key not in anagrams:
                anagrams[key] = []
            anagrams[key].append(s)

        return list(anagrams.values())

Time and Memory Complexity

The time complexity is O(nk), where n is the number of strings in strs and k is the maximum length of a string. This is due to iterating over each character of each string to count frequencies. The space complexity is O(nk), for storing the hash table and the output list of anagrams.

Explanation

This solution uses a count of characters in each string to form a unique hashable key. Strings that are anagrams of each other will have the same character count and thus be grouped together under the same key in the hash table. This approach avoids sorting each string, which can be more efficient, especially for longer strings.

Visualization Process:

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

Character Count and Grouping:
- (1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0): ["eat", "tea", "ate"]
- (1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0): ["tan", "nat"]
- (1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0): ["bat"]

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

Each string is translated into a count of its characters, which is used to group the anagrams. This method effectively organizes the strings into groups of anagrams without the need for sorting each string.