Given an array of strings, group anagrams together. 同字母异位词anagrams 指字母相同,但排列不同的字符串。
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.
求解
方法一:排序数组分类
顺序不同, 所以可以考虑将所有词的字母按顺序排列, 从而快速分组
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
HashMap<String, List<String>> map = new HashMap<String, List<String>>();
if (strs.length == 0) return new ArrayList();
for (String s : strs) {
char[] cur = s.toCharArray();
Arrays.sort(cur); // 复杂度: KlogK
String key = String.valueOf(cur);
if (!map.containsKey(key)){
map.put(key, new ArrayList<>());
}
map.get(key).add(s);
}
return new ArrayList<List<String>>(map.values());
}
}
复杂度分析
时间复杂度:O(N KlogK),其中 N是 strs 的长度,而 K 是 strs 中字符串的最大长度。当我们遍历每个字符串时,外部循环具有的复杂度为 O(N)。然后,我们在 O(KlogK) 的时间内对每个字符串排序。
空间复杂度:O(NK),排序存储在 ans 中的全部信息内容。
方法二:按计数分类
当且仅当它们的字符计数(每个字符的出现次数)相同时,两个字符串是字母异位词。
我们可以将每个字符串 s 转换为字符数 count,由26个非负整数组成,表示a,b,c 的数量等。我们使用这些计数作为哈希映射的基础。
在 Java 中,我们的字符数 count 的散列化表示将是一个用 # 字符分隔的字符串。 例如,abbccc 将表示为 #1#2#3#0#0#0 ...#0
,其中总共有26个条目。
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
if (strs.length == 0) return new ArrayList();
Map<String, List> ans = new HashMap<String, List>();
int[] count = new int[26];
for (String s : strs) {
Arrays.fill(count, 0);
for (char c : s.toCharArray()) count[c - 'a']++;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 26; i++) {
sb.append('#');
sb.append(count[i]);
}
String key = sb.toString();
if (!ans.containsKey(key)) ans.put(key, new ArrayList());
ans.get(key).add(s);
}
return new ArrayList(ans.values());
}
}
复杂度分析
时间复杂度:O(NK),其中 N 是 strs 的长度,而 K 是 strs 中字符串的最大长度。计算每个字符串的字符串大小是线性的,我们统计每个字符串。
空间复杂度:O(NK),排序存储在 ans 中的全部信息内容。