题目描述:
大致思路:
可以理解为根据条件将数组 groupBy, 而分为一组的条件为: 属于字母异位词的字符.
我们可以先实现最基本按 为相同条件分组的函数:
function groupBy<T>(arr: T[], key?: string) {
//定义map, 使用其记录是否出现相同的值
const map = new Map<any, number>();
return arr.reduce((acc, cur: any, index) => {
// 如果有传第二个参数, 则是一个对象数组, 根据对象这个属性是否相同进行分组
const val = key ? cur[key] as any : cur;
//map中有出现与当前相同的值
if (map.has(val)) {
//利用之前记录的 数组索引, 将这个重复值push进数组
acc[map.get(val)!].push(cur);
} else {
//当前值是一个新出现的值, 将其set进map, 并记录其对应的索引
map.set(val, acc.length);
//建立一个新的数组, push进 最后的结果中
acc.push([cur]);
}
return acc;
}, [] as T[][]);
}
现在要做的就是将 map.has(val)这个条件转化为题目中对应的条件
代码如下:
const getCount = (s: string, str: string) => {
let count = 0;
for (let i = 0; i < str.length; ++i) {
if (str[i] === s) {
count++;
}
}
return count;
};
const judgeStr = (str: string, targetStr: string) =>
str.length === targetStr.length
&& Array.from(str).every((s) => targetStr.includes(s) && getCount(s, targetStr) === getCount(s, str));
评论区大佬思路: 用质数表示26个字母,把字符串的各个字母相乘,这样可保证字母异位词的乘积必定是相等的
代码如下:
// 最后提交超时了, 可能是我计算乘积的算是有问题....
const judgeStr33 = (str: string, target: string) => {
if (str.length !== target.length) return false;
const letterToPrime = new Map<string, number>(
[
['a', 2],
['b', 3],
['c', 5],
['d', 7],
['e', 11],
['f', 13],
['g', 17],
['h', 19],
['i', 101],
['j', 23],
['k', 29],
['l', 31],
['m', 37],
['n', 41],
['o', 43],
['p', 47],
['q', 53],
['r', 59],
['s', 61],
['t', 67],
['u', 71],
['v', 73],
['w', 79],
['x', 83],
['y', 89],
['z', 97],
]
);
const product1 = Array.from(str).reduce((acc, cur) => acc * letterToPrime.get(cur)!, 1);
const product2 = Array.from(target).reduce((acc, cur) => acc * letterToPrime.get(cur)!, 1);
return product1 === product2;
};
最后所有代码
function groupAnagrams(strs: string[]): string[][] {
const getCount = (s: string, str: string) => {
let count = 0;
for (let i = 0; i < str.length; ++i) {
if (str[i] === s) {
count++;
}
}
return count;
};
const judgeStr = (str: string, targetStr: string) =>
str.length === targetStr.length
&& Array.from(str).every((s) => targetStr.includes(s) && getCount(s, targetStr) === getCount(s, str));
const map = new Map<string, number>();
return strs.reduce((acc, cur, index) => {
let flag = false;
if (map.has(cur)) {
flag = true;
acc[map.get(cur)!].push(cur);
} else {
map.set(cur, acc.length);
}
map.forEach((value, key) => {
if (judgeStr(key, cur) && !flag && key !== cur) {
flag = true;
if (acc[value]) {
acc[value].push(cur);
}
map.set(cur, value);
}
});
if (!flag) {
acc.push([cur]);
}
return acc;
}, [] as string[][]);
}