Go&Java算法之字母异位词分组

45 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情

字母异位词分组

给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。

字母异位词 是由重新排列源单词的字母得到的一个新单词,所有源单词中的字母通常恰好只用一次。

 

  • 示例 1:

输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]

输出: [["bat"],["nat","tan"],["ate","eat","tea"]]

  • 示例 2:

输入: strs = [""]

输出: [[""]]

  • 示例 3:

输入: strs = ["a"]

输出: [["a"]]  

提示:

1 <= strs.length <= 104

0 <= strs[i].length <= 100

strs[i] 仅包含小写字母

方法一:排序(Java)

字母相同,但排列不同的字符串,排序后都一定是相同的。因为每种字母的个数都是相同的,那么排序后的字符串就一定是相同的。

这里可以利用 stream 的 groupingBy 算子实现直接返回结果

class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        Map<String, List<String>> map = new HashMap<String, List<String>>();
        for (String str : strs) {
            char[] array = str.toCharArray();
            Arrays.sort(array);
            String key = new String(array);
            List<String> list = map.getOrDefault(key, new ArrayList<String>());
            list.add(str);
            map.put(key, list);
        }
        return new ArrayList<List<String>>(map.values());
    }
}

n:strs中字符串的数量

k:strs中字符串的最大长度

时间复杂度:O(nklogk)

空间复杂度:O(nk)

方法二:计数(Go)

由于互为字母异位词的两个字符串包含的字母相同,因此两个字符串中的相同字母出现的次数一定是相同的,故可以将每个字母出现的次数使用字符串表示,作为哈希表的键。

由于字符串只包含小写字母,因此对于每个字符串,可以使用长度为 2626 的数组记录每个字母出现的次数。

用26位的数组存储字母出现次数,map中可以以数组作为key

func groupAnagrams(strs []string) (ans [][]string) {
    // 用数组记录异位词
    mp := make(map[[26]int][]string)
    for _, str := range strs {
        cnt := conv(str)
        if _, ok := mp[cnt]; !ok {
            mp[cnt] = []string{}
        }
        mp[cnt] = append(mp[cnt], str)
    }
    for _, val := range mp {
        ans = append(ans, val)
    }
    return ans
}
func conv(s string) (ret [26]int) {
    for _, char := range s {
        ret[char - 'a']++
    }
    return 
}