◀ THE GRIND — ARRAYS & HASHING

Group Anagrams

MEDIUM✓ CHIP-TIMEDLC #49 — FULL STATEMENT ↗

The drill: Bundle the words that are anagrams of each other — same letters, shuffled — into groups; every word lands in exactly one group.

THE BRIEFING — THE FULL DRILL, IN MY OWN WORDS

A list of lowercase strings arrives, and the task is to bundle together every string that is a letter-for-letter rearrangement of another — same letters, same counts, just shuffled.

Every string in the input must land in exactly one group; a string with no anagram partners still forms its own group of one, standing alone.

The order of the groups in the output, and the order of strings within each group, is free — grouping correctly is what's judged, not any particular arrangement.

EX 01
strs = ["listen", "silent", "enlist", "tea", "ate", "car"]
[["listen", "silent", "enlist"], ["tea", "ate"], ["car"]]
EX 02
strs = [""]
[[""]]
EX 03
strs = ["a"]
[["a"]]
THE HINTS — TAKE ONLY WHAT YOU NEED
HINT 1 THE NUDGE

Two words belong together exactly when some fingerprint of theirs matches. What fingerprint survives shuffling?

HINT 2 THE STRUCTURE

Sorting a word’s letters gives a canonical form — every anagram sorts to the same string. A map from canonical form to bucket does the grouping.

HINT 3 ONE STEP FROM THE ANSWER

Sorting each word costs k·log k. Letters are only 26: a count-of-each-letter signature is the same key in O(k) — tuple it in Python, join it into a string in Java.

COACH'S BOARD — THE PATTERN, STEP BY STEP
THE FINGERPRINT SORTPATTERN · LETTER-COUNT KEYstrs = ["ab", "ba", "abc"]
ab
ba
abc
BUCKETS — LETTER-COUNT KEY → WORDS
— empty —
STEP 1

Three words: ab, ba, abc. Each gets fingerprinted by its letter counts — same fingerprint, same group.

STEP 1 / 8 · ← → WORK TOO
THE SPLITS — TWO PACES, TWO LANGUAGES
grind/group-anagrams.pyRACE PACE
LANG ▸
PACE ▸
class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        groups = {}
        for w in strs:
            counts = [0] * 26
            for ch in w:
                counts[ord(ch) - ord("a")] += 1
            groups.setdefault(tuple(counts), []).append(w)
        return list(groups.values())
TIME O(N·K)SPACE O(N·K)PYTHON · RACE PACE · 9 LN

✓ CHIP-TIMED — ALL 4 SOLUTIONS RAN GREEN AGAINST SELF-AUTHORED CASES IN CI · JDK 21 · CPYTHON 3.12 · NOTHING PUBLISHES RED