Anagrams share a sorted key. Pairwise anagram tests are \(O(n^2 k)\).
Hashing that sorted string clusters the original words automatically.
For each \(s\), append it to \(d[''.join(sorted(s))]\) and emit the value lists. One \(O(k\log k)\) sort per word buys a hash insert.
Traverse the string array, sort each string according to character lexicographical order, and get a new string.
Use the new string as key and [str] as value, and store them in the hash table (HashMap<String, List<String>>).
When the same key is encountered in subsequent traversals, add it to the corresponding value.
Take strs = ["eat", "tea", "tan", "ate", "nat", "bat"] as an example. At the end of the traversal, the state of the hash table is:
key
value
"aet"
["eat", "tea", "ate"]
"ant"
["tan", "nat"]
"abt"
["bat"]
Finally, return the value list of the hash table.
The time complexity is \(O(n\times k\times \log k)\), where \(n\) and \(k\) are the length of the string array and the maximum length of the string, respectively.
With a tiny alphabet the sort key can become a frequency tuple, dropping the \(O(k\log k)\) factor.
A length-\(26\) count (or a tuple built from it) is the key; grouping is unchanged and each word is \(O(k+C)\).
We can also change the sorting part in Solution 1 to counting, that is, use the characters in each string \(s\) and their occurrence times as key, and the string \(s\) as value to store in the hash table.
The time complexity is \(O(n\times (k + C))\). Where \(n\) and \(k\) are the length of the string array and the maximum length of the string, respectively, and \(C\) is the size of the character set. In this problem, \(C = 26\).