题目

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

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

示例 1:

输入: strs = [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”]
输出: [[“bat”],[“nat”,”tan”],[“ate”,”eat”,”tea”]]
示例 2:

输入: strs = [“”]
输出: [[“”]]
示例 3:

输入: strs = [“a”]
输出: [[“a”]]

提示:

1 <= strs.length <= 10^4
0 <= strs[i].length <= 100
strs[i] 仅包含小写字母

思路

回看之前做的思路是用26个质数表示每个字母,计算每个字符串的乘积,如果相等说明两个字符串互为“字母异位词”。在测试用例比较弱的时候的确可以过,今天再看新加的几个果然过不了了。当时还觉得自己的做法挺不错,现在看来有些搞笑…

更为方便严谨的做法是统计字符串每个字母的次数,使用统计出来的次数构造一个唯一不会冲突的字符串作为哈希表的49. 字母异位词分组 - 图1,然后对应49. 字母异位词分组 - 图2存储字母异位词。

比如对于字符串“49. 字母异位词分组 - 图3”,可以构造49. 字母异位词分组 - 图4为”49. 字母异位词分组 - 图5“,这样不会存在49. 字母异位词分组 - 图6相同而不是字母异位词的情况。

代码

  1. class Solution {
  2. public List<List<String>> groupAnagrams(String[] strs) {
  3. Map<String, List<String>> map = new HashMap<>();
  4. for (String s : strs) {
  5. char[] arr = s.toCharArray();
  6. int[] count = new int[26];
  7. for (char c : arr) {
  8. count[c - 'a']++;
  9. }
  10. StringBuilder sb = new StringBuilder();
  11. // 构造哈希表key
  12. for (int i = 0; i < 26; i++) {
  13. if (count[i] > 0) {
  14. sb.append((char) ('a' + i)).append(count[i]);
  15. }
  16. }
  17. map.computeIfAbsent(sb.toString(), k -> new ArrayList<>()).add(s);
  18. }
  19. // map.values()可以直接传入ArrayList的构造函数中,不用使用for循环
  20. List<List<String>> ans = new ArrayList<>(map.values());
  21. return ans;
  22. }
  23. }