Description
Write a method to sort an array of strings so that all the anagrams are in the same group.
Note: This problem is slightly different from the original one the book.
Example:
Input: ["eat", "tea", "tan", "ate", "nat", "bat"],
Output:
[
["ate","eat","tea"],
["nat","tan"],
["bat"]
]
Notes:
All inputs will be in lowercase.
The order of your output does not matter.
Solutions
Solution 1: Hash Table
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.
Python3 Java C++ Go TypeScript Swift
class Solution :
def groupAnagrams ( self , strs : List [ str ]) -> List [ List [ str ]]:
d = defaultdict ( list )
for s in strs :
k = '' . join ( sorted ( s ))
d [ k ] . append ( s )
return list ( d . values ())
1
2
3
4
5
6
7
8
9
10
11
12 class Solution {
public List < List < String >> groupAnagrams ( String [] strs ) {
Map < String , List < String >> d = new HashMap <> ();
for ( String s : strs ) {
char [] t = s . toCharArray ();
Arrays . sort ( t );
String k = String . valueOf ( t );
d . computeIfAbsent ( k , key -> new ArrayList <> ()). add ( s );
}
return new ArrayList <> ( d . values ());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14 class Solution {
public :
vector < vector < string >> groupAnagrams ( vector < string >& strs ) {
unordered_map < string , vector < string >> d ;
for ( auto & s : strs ) {
string k = s ;
sort ( k . begin (), k . end ());
d [ k ]. emplace_back ( s );
}
vector < vector < string >> ans ;
for ( auto & [ _ , v ] : d ) ans . emplace_back ( v );
return ans ;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13 func groupAnagrams ( strs [] string ) ( ans [][] string ) {
d := map [ string ][] string {}
for _ , s := range strs {
t := [] byte ( s )
sort . Slice ( t , func ( i , j int ) bool { return t [ i ] < t [ j ] })
k := string ( t )
d [ k ] = append ( d [ k ], s )
}
for _ , v := range d {
ans = append ( ans , v )
}
return
}
function groupAnagrams ( strs : string []) : string [][] {
const d : Map < string , string [] > = new Map ();
for ( const s of strs ) {
const k = s . split ( '' ). sort (). join ( '' );
if ( ! d . has ( k )) {
d . set ( k , []);
}
d . get ( k ) ! . push ( s );
}
return Array . from ( d . values ());
}
class Solution {
func groupAnagrams ( _ strs : [ String ]) -> [[ String ]] {
var d = [ String : [ String ]]()
for s in strs {
let t = String ( s . sorted ())
d [ t , default : []]. append ( s )
}
return Array ( d . values )
}
}
Solution 2: Counting
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\) .
Python3 Java C++ Go
class Solution :
def groupAnagrams ( self , strs : List [ str ]) -> List [ List [ str ]]:
d = defaultdict ( list )
for s in strs :
cnt = [ 0 ] * 26
for c in s :
cnt [ ord ( c ) - ord ( 'a' )] += 1
d [ tuple ( cnt )] . append ( s )
return list ( d . values ())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 class Solution {
public List < List < String >> groupAnagrams ( String [] strs ) {
Map < String , List < String >> d = new HashMap <> ();
for ( String s : strs ) {
int [] cnt = new int [ 26 ] ;
for ( int i = 0 ; i < s . length (); ++ i ) {
++ cnt [ s . charAt ( i ) - 'a' ] ;
}
StringBuilder sb = new StringBuilder ();
for ( int i = 0 ; i < 26 ; ++ i ) {
if ( cnt [ i ] > 0 ) {
sb . append (( char ) ( 'a' + i )). append ( cnt [ i ] );
}
}
String k = sb . toString ();
d . computeIfAbsent ( k , key -> new ArrayList <> ()). add ( s );
}
return new ArrayList <> ( d . values ());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 class Solution {
public :
vector < vector < string >> groupAnagrams ( vector < string >& strs ) {
unordered_map < string , vector < string >> d ;
for ( auto & s : strs ) {
int cnt [ 26 ] = { 0 };
for ( auto & c : s ) ++ cnt [ c - 'a' ];
string k ;
for ( int i = 0 ; i < 26 ; ++ i ) {
if ( cnt [ i ]) {
k += 'a' + i ;
k += to_string ( cnt [ i ]);
}
}
d [ k ]. emplace_back ( s );
}
vector < vector < string >> ans ;
for ( auto & [ _ , v ] : d ) ans . emplace_back ( v );
return ans ;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14 func groupAnagrams ( strs [] string ) ( ans [][] string ) {
d := map [[ 26 ] int ][] string {}
for _ , s := range strs {
cnt := [ 26 ] int {}
for _ , c := range s {
cnt [ c - 'a' ] ++
}
d [ cnt ] = append ( d [ cnt ], s )
}
for _ , v := range d {
ans = append ( ans , v )
}
return
}