问题描述
- Given an array of strings, group anagrams together.
- Example:
Input: [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”],
Output:
[
[“ate”,”eat”,”tea”],
[“nat”,”tan”],
[“bat”]
]
- Note :
All inputs will be in lowercase.
The order of your output does not matter. - 地址
问题分析
- 该题是 HashMap 的应用问题
方法一:
首先明确一个特性:如果两串互相为 Anagrams ,那么这两串按照字典序排序后的结果一致。- 利用HashMap key存当前字符串排序后的结果,value 存储当前字符串,这样便可以把所有互为 Anagrams 的串放在一起。
时间复杂度: O(NKlogK)
方法二:
首先明确一个特性:如果两串互为 Anagrams ,那么这两串按照次数及字典序序列化的结果一致。
何为按照次数及字典序序列化呢 ?
如baadccc
可以序列化为2#1#3#4#
,可以利用count[26] 来实现,既可以保证顺序,又能统计次数。- 利用HashMap key存当前字符串序列化后的结果,value 存储当前字符串,这样便可以把所有互为 Anagrams 的串放在一起。
时间复杂度: O(NK),但实际上如果key是字符串的话,hash的效率会大大下降,反而不如方法1。
经验教训
- HashMap 进行映射时, key 到底存什么才能使问题得到简化
- 何为按照次数及字典序序列化
return new ArrayList(map.values());
HashMap 的 values()方法,以及ArrayList 的构造方法。
代码实现
- 方法一:
public List<List<String>> groupAnagrams(String[] strs) {
if (strs == null || strs.length == 0) {
return new ArrayList<>();
}
HashMap<String, List<String>> map = new HashMap<>();
for (String str : strs) {
char[] chs = str.toCharArray();
Arrays.sort(chs);
String newStr = new String(chs);
if (! map.containsKey(newStr)) {
map.put(newStr, new ArrayList<String>());
}
map.get(newStr).add(str);
}
return new ArrayList(map.values());
}
- 方法二:
public List<List<String>> groupAnagrams(String[] strs) {
if (strs == null || strs.length == 0) {
return new ArrayList<>();
}
HashMap<String, List<String>> map = new HashMap<>();
for (String str : strs) {
String cntStr = countString(str);
if (! map.containsKey(cntStr)) {
map.put(cntStr, new ArrayList<String>());
}
map.get(cntStr).add(str);
}
return new ArrayList(map.values());
}
public String countString(String str) {
int[] count = new int[26];
for (char ch : str.toCharArray()) {
++count[ch - 'a'];
}
StringBuilder res = new StringBuilder();
for (int i = 0; i < 26; i++) {
res.append(count[i]).append("#");
}
return res.toString();
}