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"]
]

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;
    }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值