每日一道算法 Day5

88 阅读1分钟

题目描述

image.png

大致思路, 经过昨天那道题后发现解决这种问题使用双指针更加简单, 于是思路为for循环(i)单层遍历数组, 将数组从大到小排序, 定义一头一尾指针 j与k, 然后拿到 val = nums[i] + nums[j] + nums[k]. 如果val < target, 则j++, val > targetk--, val === target 则直接retrun val. 需要注意的点是 i、j、k 三个值不能相等。该部分代码如下:

const tmp: number[] = [];
  for (let i = 1; i < nums.length - 1; ++i) {
    let j = 0;
    let k = nums.length - 1;
    while (j < k) {
      const val = nums[i] + nums[j] + nums[k];
      if (val === target) return target;
      if (val < target) {
        if (++j === i) ++j;
      }
      if ((val > target)) {
        if (--k === i) --k;
      }
      tmp.push(val);
    }
  }

拿到数组和的集合后需要做的事情就是取到 集合每个元素与target差值的绝对值的集合中最小的那个值的 index, 最后tmp[index]即为最接近的数据

该部分代码:

const min = tmp.map((item) => Math.abs(target - item)).sort((a, b) => a - b)[0];
const index = tmp.map((item) => Math.abs(target - item)).findIndex((item) => item === min);

最后主题函数:

export function threeSumClosest(nums: number[], target: number): number {
  if (nums.length < 3) return 0;
  nums.sort((a, b) => a - b);
  const tmp: number[] = [];
  for (let i = 1; i < nums.length - 1; ++i) {
    let j = 0;
    let k = nums.length - 1;
    while (j < k) {
      const val = nums[i] + nums[j] + nums[k];
      if (val === target) return target;
      if (val < target) {
        if (++j === i) ++j;
      }
      if ((val > target)) {
        if (--k === i) --k;
      }
      tmp.push(val);
    }
  }
  const min = tmp.map((item) => Math.abs(target - item)).sort((a, b) => a - b)[0];
  const index = tmp.map((item) => Math.abs(target - item)).findIndex((item) => item === min);
  return tmp[index];
}


//测试用例:
test('threeSumClosest', () => {
    expect(threeSumClosest([-1, 2, 1, -4], 1)).toBe(2);
    expect(threeSumClosest([1, 4, 3, -4, 2], 1)).toBe(1);
    expect(threeSumClosest([0, 0, 0, 1], 1)).toBe(1);
    expect(threeSumClosest([0, 0, 0], 1)).toBe(0);
});

最后总结: 神奇的双指针...