每日一道算法Day29 -- 根据条件对数组分组

322 阅读2分钟

题目描述:

image.png

大致思路:

可以理解为根据条件将数组 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[][]);
}