#49 Group Anagrams
the problem
In plain words
Group the strings that are anagrams of each other. Return the groups in any order.
in strs = ["eat","tea","tan","ate","nat","bat"]
out [["bat"],["nat","tan"],["ate","eat","tea"]]
in strs = [""]
out [[""]]
- 1 ≤ strs.length ≤ 10⁴
- 0 ≤ strs[i].length ≤ 100
- Lowercase English letters
your turn
Try it before you peek
Read the examples, say the brute force out loud, then write code: here or on LeetCode ↗. Stuck for 20 minutes? Open one hint at a time.
Solve it in the browser
LeetCode-style: complete the class. Compiled by the real javac (Java 17) and judged right here — nothing is sent anywhere.
Solutions are hidden so you can try first. Even 20 minutes of real effort makes the answer stick far better than reading it.
Marking the problem solved, or opening every hint, also shows it.
the aha
Key insight
patternGroup by a canonical keyFrequency counting
Give every word a canonical key that's identical for all its anagrams — its sorted letters, or its 26 letter counts — and bucket words by key in a HashMap.
solutions
From brute force to optimal
Keep a list of group signatures (sorted letters) and scan it for each word.
- sig = sorted(word).
- indexOf(sig) in the signature list (a linear scan).
- Append to that group or start a new one.
Each of n words scans up to g groups comparing k-length signatures, plus sorting each word.
All words and signatures are stored.
class Solution { public List<List<String>> groupAnagrams(String[] strs) { List<List<String>> groups = new ArrayList<>(); List<String> signatures = new ArrayList<>(); // one sorted signature per group for (String s : strs) { String sig = sorted(s); int g = signatures.indexOf(sig); // linear scan over groups if (g < 0) { signatures.add(sig); groups.add(new ArrayList<>()); g = groups.size() - 1; } groups.get(g).add(s); } return groups; } private String sorted(String s) { char[] c = s.toCharArray(); Arrays.sort(c); return new String(c); }}"eat", "tea" and "ate" all sort to "aet".
- For each word: sort its chars → key.
- map.computeIfAbsent(key, new list).add(word).
- Return the map's values.
n words, each sorted in k log k (k = max length).
Every word and key is stored.
class Solution { public List<List<String>> groupAnagrams(String[] strs) { Map<String, List<String>> groups = new HashMap<>(); for (String s : strs) { char[] chars = s.toCharArray(); Arrays.sort(chars); // "eat", "tea", "ate" -> "aet" String key = new String(chars); groups.computeIfAbsent(key, k -> new ArrayList<>()).add(s); } return new ArrayList<>(groups.values()); }}Build the 26 counts of each word and use them as the key.
- For each word: count letters into int[26].
- key = Arrays.toString(count).
- Bucket by key.
Counting is linear in the word; building the key costs 26 more steps.
The groups plus one fixed-size key per group.
class Solution { public List<List<String>> groupAnagrams(String[] strs) { Map<String, List<String>> groups = new HashMap<>(); for (String s : strs) { int[] count = new int[26]; for (int i = 0; i < s.length(); i++) count[s.charAt(i) - 'a']++; String key = Arrays.toString(count); // "[1, 0, 0, 0, 1, ...]": same for all anagrams groups.computeIfAbsent(key, k -> new ArrayList<>()).add(s); } return new ArrayList<>(groups.values()); }}Dry run
Keys are drawn short (a1 e1 t1); in Java the key is `Arrays.toString(count)`.
in the room
How to say it in the interview
talk track
- Say: "I need a key that's equal for anagrams and different otherwise" — then offer both keys.
- Note the trade-off: sorted keys are simpler; count keys win when words are long.
traps
- Using
char[]orint[]itself as a HashMap key — arrays use identity hashCode, so equal contents land in different buckets. Convert to a String. - Building the count key by just concatenating digits without separators: counts like [1, 11] and [11, 1] would collide.
what they ask next
Follow-ups
Why is computeIfAbsent nice here?
It creates the list only when the key is new and returns it either way — one line instead of get / null-check / put.
Which key is better in practice?
For short words the sorted key is simpler and often as fast; the count key wins asymptotically when words are long (k ≫ 26).
before you submit
Edge cases to test
- An empty string is a word too: [""] → [[""]].
- Duplicate words stay as separate entries in the same group.
- Count keys need separators: counts [1, 11] and [11, 1] must not collide.
practise next
Similar problems
- #242Valid AnagramEasyin Arrays & Strings
- #205Isomorphic StringsEasyin Hashing
- #347Top K Frequent ElementsMediumin Heaps