给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。
字母异位词 是由重新排列源单词的所有字母得到的一个新单词。
示例 1:
输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"] 输出: [["bat"],["nat","tan"],["ate","eat","tea"]]
示例 2:
输入: strs = [""] 输出: [[""]]
示例 3:
输入: strs = ["a"] 输出: [["a"]]
题解1 计数
思路
字母异位词的意思就是说一个单词,他们每个字母出现的次数一样。这样的话,需要知道他们每个字母出现的次数,所以需要计数,然后吧这个计数当做唯一标识缓存下来,遇到不同的就添加到列表里,最后返回二维数组即可。
如何把计数当做唯一标识呢?因为题干表示只存在小写字母,所以可以利用字符的 ASCII 码来比较字符的先后顺序,然后保存在长度为26的数组中,最后把这个数组调用 toString 方法来当做唯一标识。缓存的话同样可以使用哈希表。
代码
function groupAnagrams(strs: string[]): string[][] {
const map: Map<string, string[]> = new Map();
for (const str of strs) {
const mapKeyArr: number[] = new Array(26).fill(0);
for (const char of str) {
const index = char.charCodeAt(0) - 'a'.charCodeAt(0);
mapKeyArr[index]++;
}
const mapKey: string = mapKeyArr.toString();
if (map.has(mapKey)) {
const arr: string[] = map.get(mapKey);
arr.push(str);
map.set(mapKey, arr);
} else {
map.set(mapKey, [str]);
}
}
const result: string[][] = [];
for (const item of map.values()) {
result.push(item);
}
return result;
};
时空复杂度分析
时间复杂度:数组每个字符都要遍历,每个字符最长为100,所以为 O(100N),忽略常数所以为 O(N)
空间复杂度:额外使用哈希表来缓存,所以为 O(N)
题解2 排序
思路
如果两个词是异位词,那么它们从 a 到 z 排序,这个字符串是一样的。同样将这个字符串当做哈希表的唯一标识缓存下来。
代码
function groupAnagrams(strs: string[]): string[][] {
const map: Map<string, string[]> = new Map();
for (const str of strs) {
const strArr: string[] = Array.from(str);
strArr.sort();
const mapKey: string = strArr.toString();
const list: string[] = map.has(mapKey) ? map.get(mapKey) : [];
list.push(str);
map.set(mapKey, list);
}
const result: string[][] = [];
for (const item of map.values()) {
result.push(item);
}
return result;
};
时空复杂度分析
时间复杂度:每个字符长度为 k 需要排序,所以排序方面的时间复杂度为 k logk,总的时间复杂度为 O(n klogk)
空间复杂度:额外使用哈希表来缓存,所以为 O(N)