leetcode题解-49. Group Anagrams

题目:Given an array of strings, group anagrams together.For example, given: [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”],
Return: [ [“ate”, “eat”,”tea”], [“nat”,”tan”], [“bat”] ]

思路1,使用前面的题目来判断两个字符串是否为anagrams,这样有两种做法,第一个是循环嵌套,判断字符串间关系,并把已经识别过的字符串记录下来,以免重复判断,代码入下:

    public static List<List> groupAnagrams(String[] strs) {
        List<List> res = new ArrayList<List>();
        //存储已经识别过的字符串
        Set used = new HashSet<>();
        for(int i=0; iif(used.contains(i))
                continue;
            List ana = new ArrayList<>();
            used.add(i);
            ana.add(strs[i]);
            for(int j=i+1; jif(used.contains(j))
                    continue;
                if(isAnagram1(strs[i], strs[j])){
                    ana.add(strs[j]);
                    used.add(j);
                }
            }
            res.add(ana);
        }
        return res;
    }

另外一个方法就是,使用hashMap来存储识别过得字符串,然后遍历,对数组中的每一个字符串都使用hashMap的键值进行匹配,这样的缺点是非常耗时。

public static ListString>> groupAnagrams2(String[] strs) {
        ListString>> res = new ArrayListString>>();
        Map<String, List<String>> used = new HashMap<>();
        for(int i=0; ifalse;
            for(String ss : used.keySet()){
                if(isAnagram1(strs[i], ss)){
                    List<String> aa = used.get(ss);
                    aa.add(strs[i]);
                    used.put(ss, aa);
                    flag = true;
                    break;
                }
            }
            if(flag == false){
            List<String> aa = new ArrayList<>();
            aa.add(strs[i]);
            used.put(strs[i], aa);
            }
        }
        for(String ss:used.keySet())
            res.add(used.get(ss));
        return res;
    }

以上两种方法中的isAnagram1都是之前一个题目中写的效率最高函数。如下。但是发现最终提交结果时都显示超时。说明一开始这种借用之前题目成果的办法并不适用。痛定思痛,接下来想一想有什么改进办法。

public static boolean isAnagram1(String s, String t) {
        if(s.length() != t.length())
            return false;
        int [] tmp = new int[26];
        for(char c : s.toCharArray())
            tmp[c-'a'] ++;
        for(char c:t.toCharArray())
            tmp[c-'a'] --;
        for(int a:tmp)
            if(a!=0)
                return false;
        return true;
    }

首先按照方法二进行改进,对每个字符串进行遍历的时候,先对其进行排序然后将其作为键值保存到hashMap中,这样就可以省去麻烦的判断过程,而直接使用hashMap.containsKey方法来达到判断的效果。节省了很多循环的时间。但这样的改进带来的提升有限,只击败了15%的用户

    public ListString>> groupAnagrams3(String[] strs) {
        if(strs==null || strs.length == 0){
            return new ArrayListString>>();
        }
        HashMap<String, List<String>> map = new HashMap<String, List<String>>();
        //Arrays.sort(strs);
        for (String s:strs) {
            char[] ca = s.toCharArray();
            Arrays.sort(ca);
            String keyStr = String.valueOf(ca);
            if(!map.containsKey(keyStr))
                map.put(keyStr, new ArrayList<String>());
            map.get(keyStr).add(s);
        }

        for(String key: map.keySet()) {
            Collections.sort(map.get(key));
        }
        return new ArrayListString>>(map.values());
    }

最后,还有一种极为巧妙的方法,使用26个质数与字母一一对应相乘作为字符串的键值保存到hashMap中。这样就省去了字符串的排序等操作,而且这种方法省去了最后对hashMap遍历生成列表的过程也节省了很多时间。这种方法击败了99%的用户。

    public List> groupAnagrams4(String[] strs) {
        int[] prime = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103};//最多10609个z
        List> res = new ArrayList<>();
        HashMap map = new HashMap<>();
        for (String s : strs) {
            int key = 1;
            for (char c : s.toCharArray()) {
                key *= prime[c - 'a'];
            }
            List t;
            if (map.containsKey(key)) {
                t = res.get(map.get(key));
            } else {
                t = new ArrayList<>();
                res.add(t);
                map.put(key, res.size() - 1);
            }
            t.add(s);
        }
        return res;
    }

你可能感兴趣的:(leetcode刷题)