👉️ 力扣原文
题目
给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。
字母异位词 是由重新排列源单词的字母得到的一个新单词,所有源单词中的字母通常恰好只用一次。
字母异位词是指由相同的字母按照不同的顺序组成的单词,比如 “tea” 和 “eat” 就是字母异位词。在字母异位词分组问题中,需要把给定的一组字符串按照它们是否是字母异位词进行分组。
举个例子,如果我们有一个字符串数组 [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”],我们需要把其中所有的字母异位词分成一组。因为 “eat” 和 “ate”、“tea” 是字母异位词,所以它们应该被放到同一组;同理,“tan”、“nat” 也应该被放到一组;而 “bat” 是一个孤立的单词,应该自成一组。因此最终得到的分组结果是 [[“eat”,“ate”,“tea”],[“tan”,“nat”],[“bat”]]。
示例
输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
输出: [["bat"],["nat","tan"],["ate","eat","tea"]]
输入: strs = [""]
输出: [[""]]
输入: strs = ["a"]
输出: [["a"]]
分析思路1
排序:
创建一个 HashMap,用于存储每个字母异位词对应的单词列表。
遍历字符串数组中的每个单词,把它们转换成字符数组并排序,得到一个按字典序排列的相同字符串。
判断这个相同字符串是否已经存在于 HashMap 中,如果不存在,则创建一个新的键值对;否则在对应的值列表中添加该单词。
最后返回所有的值列表即可。
题解1
public class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
if (strs == null || strs.length == 0) return new ArrayList<>();
Map<String, List<String>> map = new HashMap<>();
for (String s : strs) {
char[] ch = s.toCharArray();
Arrays.sort(ch);
String key = String.valueOf(ch);
if (!map.containsKey(key)){
map.put(key, new ArrayList<>());
}
map.get(key).add(s);
}
return new ArrayList<>(map.values());
}
}
执行结果
分析思路2
计数:
由于互为字母异位词的两个字符串包含的字母相同,因此两个字符串中的相同字母出现的次数一定是相同的,故可以将每个字母出现的次数使用字符串表示,作为哈希表的键。
由于字符串只包含小写字母,因此对于每个字符串,可以使用长度为 262626 的数组记录每个字母出现的次数。
题解2
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
Map<String, List<String>> map = new HashMap<String, List<String>>();
for (String str : strs) {
int[] counts = new int[26];
int length = str.length();
for (int i = 0; i < length; i++) {
counts[str.charAt(i) - 'a']++;
}
// 将每个出现次数大于 0 的字母和出现次数按顺序拼接成字符串,作为哈希表的键
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 26; i++) {
if (counts[i] != 0) {
sb.append((char) ('a' + i));
sb.append(counts[i]);
}
}
String key = sb.toString();
List<String> list = map.getOrDefault(key, new ArrayList<String>());
list.add(str);
map.put(key, list);
}
return new ArrayList<List<String>>(map.values());
}
}
执行结果