每日一道算法 Day4

198 阅读1分钟

题目描述如下:

image.png

大致思路: 将其转化为 nums[i] = nums[j] + nums[k];

写出第一个辅助函数, 接收一个数组和一个数字, 返回数组中任意两个元素的和等于该数字的集合

export function getArrByAdd(arr: number[], num: number) {
  const map = new Map<number, number>();
  const tmp: number[] = [];
  for (let i = 0; i < arr.length; ++i) {
    // 2. 如果map中有当前值, 即有与之前存储的值的和等于目标值, 并且判断之前有没有已经存储过该值
    if (map.has(arr[i]) && !tmp.includes(arr[i])) {
      tmp.push(arr[map.get(arr[i])!]);
      tmp.push(arr[i]);
    }
    // 1. 存储数组中所有元素与目标值的差值
    map.set(num - arr[i], i);
  }
  return tmp;
}

//测试代码如下:
test('getArrByAdd', () => {
    expect(getArrByAdd([1, 2, 3, 4], 3)).toEqual([1, 2]);
    expect(getArrByAdd([1, 2, 3, 4], 5)).toEqual([2, 3, 1, 4]);
    expect(getArrByAdd([1, 2, 3, 4, 5, 5], 6)).toEqual([2, 4, 1, 5]);

    expect(getArrByAdd([0, 1, 2, -1, -4], 1)).toEqual([0, 1, 2, -1]);
    expect(getArrByAdd([-1, 1, 2, -1, -4], 0)).toEqual([-1, 1]);
  });

第二个辅助函数, 获取相反数, 即 nums[j] + nums[k] + (-[nums]) = 0;

export function getOppositeNumber(num: number) {
  return ~num + 1;
}

第三个辅助函数, 移出数组中某个指定元素, 防止最后的结果出现重复项

export function removeArr<T>(arr: T[], value: T) {
  let index = arr.findIndex((p) => p === value);
  return arr.filter((val, _index) => index !== _index);
}

最后主体函数

export function threeSum(nums: number[]): number[][] {
  const res: number[][] = [];
  //边界情况
  if (nums.length < 3) return [];
  let list = nums;
  nums.forEach((item) => {
    let tmp: number[] = [];
    //
    list = removeArr(list, item);
    //获取与 item 的 和为 0 的数组元素, 需要剔除之前已经计算的项, 防止重复
    tmp = (getArrByAdd(list, getOppositeNumber(item)));
    if (tmp.length > 0) {
      for (let i = 0; i < tmp.length; i += 2) {
      //这里之前的函数设计的是返回一维数组, 所以需要这么处理, 其实应该也返回二维数组的
        const val = [item, ...tmp.slice(i, i + 2)].sort((a, b) => a - b);
        let flag = true;
        if (res.length) {
          //防止重复项
          res.forEach((item) => {
            if (item[0] === val[0] && item[1] === val[1] && item[2] === val[2]) {
              flag = false;
            }
          });
        }
        flag && res.push(val);
      }
    }
  });
  return res;
}

//单元测试代码
  test('threeSum', () => {
    expect(threeSum([])).toEqual([]);
    expect(threeSum([0])).toEqual([]);
    expect(threeSum([0, 0, 0])).toEqual([[0, 0, 0]]);
    expect(threeSum([1, 2, 4])).toEqual([]);
    expect(threeSum([-1, 0, 1, 2, -1, -4])).toEqual([[-1, 0, 1], [-1, -1, 2]]);
  });