LeetCode – Group Anagrams (Java)

Given an array of strings, return all groups of strings that are anagrams.

Analysis

An anagram is a type of word play, the result of rearranging the letters of a word or phrase to produce a new word or phrase, using all the original letters exactly once; for example, Torchwood can be rearranged into Doctor Who.

If two strings are anagram to each other, their sorted sequence is the same.

Updated on 5/1/2016.

Java Solution

public List<List<String>> groupAnagrams(String[] strs) {
    List<List<String>> result = new ArrayList<List<String>>();
 
    HashMap<String, ArrayList<String>> map = new HashMap<String, ArrayList<String>>();
    for(String str: strs){
        char[] arr = new char[26];
        for(int i=0; i<str.length(); i++){
            arr[str.charAt(i)-'a']++;
        }
        String ns = new String(arr);
 
        if(map.containsKey(ns)){
            map.get(ns).add(str);
        }else{
            ArrayList<String> al = new ArrayList<String>();
            al.add(str);
            map.put(ns, al);
        }
    }
 
    result.addAll(map.values());
 
    return result;
}

Time Complexity

If the average length of verbs is m and array length is n, then the time is O(n*m).

Category >> Algorithms >> Interview  
If you want someone to read your code, please put the code inside <pre><code> and </code></pre> tags. For example:
<pre><code> 
String foo = "bar";
</code></pre>

  1. Satish on 2015-7-12

    public static boolean anagram(String str1, String str2) {

    if (str1.length() != str2.length()) {

    return false;

    }

    HashMap buff = new HashMap();

    for (int i = 0; i < str1.length(); i++) {

    char c1 = str1.charAt(i);

    char c2 = str2.charAt(i);

    if (buff.keySet().contains(c1)) {

    int count = buff.get(c1) + 1;

    if (count == 0) {

    buff.remove(c1);

    } else {

    buff.put(c1, count);

    }

    } else {

    buff.put(c1, 1);

    }

    if (buff.keySet().contains(c2)) {

    int count = buff.get(c2) – 1;

    if (count == 0) {

    buff.remove(c2);

    } else {

    buff.put(c2, count);

    }

    } else {

    buff.put(c2, -1);

    }

    }

    return buff.size() == 0;

    }

  2. Chris on 2015-7-14

    Why cannot we use the version below?

    public static boolean anagram(String str1, String str2) {
    str1 = str1.replaceAll(“\s+”,””).toUpperCase();
    str2 = str2.replaceAll(“\s+”,””).toUpperCase();
    char[] cStr1 = str1.toCharArray();
    char[] cStr2 = str2.toCharArray();
    Arrays.sort(cStr1);
    Arrays.sort(cStr2);
    return String.valueOf(cStr1).equals(String.valueOf(cStr2));
    }

  3. ThinkFree on 2015-8-13

    That’s cool.
    However, I had one doubt. Let say a word “RAT” is given. there are six possible combinations of it. RAT, RTA, TRA, TAR, ART, ATR. Now out of all these anagram combinations, what is the most efficient way to find out the valid english words? (given that we have access to dictionary, how the comparison will work?)

  4. Jeff Guo on 2015-10-17

    Sorting is O(nlgn), here is the O(n) one.

    public static bool IsAnagram(string str1, string str2) {

    if(str1.Length != str2.Length)
    return false;

    int[] counter = new int[256];

    foreach(char c in str1)
    {
    counter[c]++;
    }

    foreach(char c in str2)
    {
    counter[c]–;
    }

    for(int i =0; i 0)
    return false;
    }

    return true;
    }

  5. Suriya on 2015-10-19

    It is more performance efficient to not use String utils. Try checking the time of execution and you will know the rest.

  6. Razvan Madalin MATEI on 2016-3-25

    A smarter solution is to use a hash function that applied to a word and any of its anagrams, will result in the same hash value. Such a hash can be constructed like this: assign a prime number to all the letters in the alphabet: a->2, b->3, c->5, d->7, etc. Construct the hash value of a string by multiplying the equivalent prime numbers.

  7. Caleb on 2016-7-27

    Hi, dear programmer! I’m a fresh bird in practicing leetcode. What is the meaning of the following code? (Since the type in arr is char, then how is it possible to do “arr[ ] ++” in the for loop? Thank you!
    char[] arr = new char[26];
    for(int i=0; i<str.length(); i++){
    arr[str.charAt(i)-'a']++;
    }

  8. Souradeep Barua on 2016-8-14

    I tried this but it was much slower than the solution given here. I guess the multiplication takes more time for large words.

  9. mike on 2016-11-15

    if there are some words which have some characters appear more than 65535 times, will the char[] be a problem

  10. Nick. W on 2016-11-19

    The posted solution assumes strings in input array are all lower case between ‘a’ to ‘z’. ‘arr’ array holds the count of occurrences of characters from ‘a’ to ‘z’ for each string in input array.

  11. Nick. W on 2016-11-20

    Use int[] array and codePointAt to calculate a key. This also relaxes the constrain on the character range of input strings.

    int []cArry = new int[128];
    for (int i=0; i < str.length(); i++){
    cArry[str.codePointAt(i)]++;
    }
    String key = new String(cArry,0,cArry.length);

  12. Anant Bobde on 2017-1-4

    here is one more approach

    Take all letters, sort them, return a String. All anagrams of the same letters will have the same keys.

    With that key system, the basic code can be come simpler with:

    private static final String anagramKey(String word) {

    word = word.toLowerCase();

    char[] chars = word.toCharArray();

    Arrays.sort(chars);

    return new String(chars);

    }

    HashMap<String,List> matchMap = new HashMap();

    for (String word : args) {

    String key = anagramKey(word);

    if (!matchMap.containsKey(key)) {

    matchMap.put(key, new ArrayList());

    }

    matchMap.get(key).add(word);

    }

    System.out.println(matchMap);

  13. Ted on 2017-4-4

    this is just checking for anagram… the question is grouping same anagram together with an array of strings…

Leave a comment

*