Group Anagrams

来源:互联网 发布:2D动画软件 编辑:程序博客网 时间:2024/06/05 17:05

原题:

Given an array of strings, group anagrams together.

For example, given: ["eat", "tea", "tan", "ate", "nat", "bat"],
Return:

[  ["ate", "eat","tea"],  ["nat","tan"],  ["bat"]]

Note: All inputs will be in lower-case.

即对给定字符串数组进行分类,把由相同字母(字母和字母数量都相同)的字符串分到一类。


思考过程:

对于这种需要进行比较的问题,用人脑解决需要记忆,那用程序解决会用到哈希表。一开始想麻烦了,是一个超时的思路:每类字符串对应一个哈希表。大致上是遍历整个字符串数组,将字符串与现在已经有的哈希表比较,如果和哪个哈希表匹配上了(字母和字母数量都匹配上),那就把它放到这个哈希表对应的字符串集合里。这里遇到很多问题,比如和哈希表进行匹配时,要匹配字母和字母数量,就不容易记录。我用的办法是哈希表里key为char,value为int表示该char在此哈希表出现的次数。那最后匹配完还要保证哈希表所有的字符都恰好匹配,也就是遍历哈希表,看它是否所有元素value为0。最后终于没有bug了,当然超时了。时间复杂度O(s^2)(s表示字符串数组字符个数)。代码如下:

public List<List<String>> groupAnagramsTLE(String[] strs) {        if (strs.length == 0) return null;        List<List<String>> ret = new ArrayList<>();        List<Map<Character,Integer>> maps = new ArrayList<>();        Map<Character,Integer> map = new HashMap<>();//哈希表存的是这个字符串有哪些字符以及有多少个        int len = strs[0].length();        mapsPutString(maps,strs[0]);//初始化List<Map>        listAddString(ret,strs[0]);//初始化结果集        for (int i = 1;i < strs.length;i++){//i表示字符串序号            boolean isGroupExist = false;//判断是否有能匹配的,如果没有,新建关于它的哈希表            String s = strs[i];            for (int k = 0; k < maps.size(); k++) {//k表示哈希表序号                if (s.length() < maps.get(k).size()) continue;//提前过滤一下                boolean isMatch = true;//判断第i个字符串和第k个哈希表是否匹配                Map<Character,Integer> hasMap1 = new HashMap<>();                hasMap1.putAll(maps.get(k));                for (int j = 0;j < s.length();j++){//j表示字符序号                    char c = s.charAt(j);                    if (!hasMap1.containsKey(c) || hasMap1.get(c) == 0) isMatch = false;                    else hasMap1.put(c,hasMap1.get(c) - 1);                }                for (Map.Entry<Character,Integer> entry : hasMap1.entrySet())//遍历哈希表确保哈希表中所有元素都匹配过了。                    if (entry.getValue() != 0) isMatch = false;                if (isMatch){                    ret.get(k).add(s);                    isGroupExist = true;                    break;                }            }            if (!isGroupExist) {                mapsPutString(maps,s);                listAddString(ret,s);            }        }        return ret;    }

后来知道可以将每个字符串排序(按字母表顺序),哈希表里存储字符串就可以了,每次匹配时只需将字符串排序,看哈希表里是否有排好序的字符串就可以了。我算了一下时间复杂度为O(sbloga)(s是字符串数组字符个数,a是每个字符串字符个数,b是字符串个数,a*b = s),accepted了。解题思路见代码注释。


结果代码:

public List<List<String>> groupAnagrams(String[] strs) {        List<List<String>> ret = new ArrayList<>();        Map<String,Integer> hasMap = new HashMap<>();        for (int i = 0,j = 0;i < strs.length;i++){//i用来遍历字符串数组,j用来标记哈希表中的字符串对应结果集的索引。            String str = strs[i];            char[] chars = str.toCharArray();//之所以这么做是因为Arrays.sort()只能对数组进行操作            Arrays.sort(chars);            String s = String.valueOf(chars);            if (hasMap.containsKey(s))//如果哈希表里有,加入结果集                ret.get(hasMap.get(s)).add(str);            else {//哈希表里没有,将str存入哈希表,value为j(j - 1表示哈希表里之前有多少个字符串)                List<String> strings = new ArrayList<>();                strings.add(str);ret.add(strings);                hasMap.put(s,j);                j++;            }        }        return ret;    }