「前端刷题」16. 最接近的三数之和

169 阅读1分钟

这是我参与8月更文挑战的第16天,活动详情查看:8月更文挑战

题目

给定一个包括 n 个整数的数组 nums和 一个目标值 target。找出 nums中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。

 

示例:

**输入:**nums = [-1,2,1,-4], target = 1 **输出:**2 **解释:**与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。

 

提示:

  • 3 <= nums.length <= 10^3
  • -10^3 <= nums[i] <= 10^3
  • -10^4 <= target <= 10^4

解题思路

思路1

  • 先将数组从小到大排序,便于微调 sum 的大小。
  • 从左到右遍历,先固定一个数,剩下的部分,用头尾双指针扫描
  • 如果 sum 大于目标值,就右指针左移,使 sum 变小,否则左指针右移,sum 变大。
  • 再看 abs(sum - target) 是否比之前更小了,如果是,将当前 sum 更新给 res
  • 遍历结束,就有了最接近目标值的 sum
var threeSumClosest = function (nums, target) {
  nums.sort((a, b) => a - b);
  let res = nums[0] + nums[1] + nums[nums.length - 1];

  for (let i = 0; i < nums.length - 2; i++) {
    const n1 = nums[i];
    let l = i + 1;
    let r = nums.length - 1;
    while (l < r) {
      const n2 = nums[l];
      const n3 = nums[r];
      const sum = n1 + n2 + n3;
      if (sum > target) {
        r--;
      } else {
        l++;
      }
      if (Math.abs(sum - target) < Math.abs(res - target)) {
        res = sum;
      }
    }
  }
  return res;
};

思路2

  • 排序固定一个值左右指针向中间逼近
  • 数组q三数和target差作key存入q
    • 三数和 >= target,右指针左移
    • 三数和 < target, 左指针右移
  • find顺序找到第一个不为undefined元素即结果
var threeSumClosest = function(nums, target, q = []) {
    nums.sort((a, b) => a - b)
    for (var i = 0; i < nums.length - 1; i++) {
        var l = i + 1, r = nums.length - 1
        while(l < r) {
            var sum = nums[i] + nums[l] + nums[r]
            sum >= target ? (q[sum - target] = sum, r--) : (q[target - sum] = sum, l++)
        }
    }
    return q.find(v=>v!==undefined)
};

思路3

  • 确定第一个数,在左右指针移动过程中,更新与target差值最小的结果
  • 技巧
    • 排序原数组
      • nums[right] >= nums[left]
      • 确定一个数 x
        • res = x + nums[left] + nums[right]
      • 当 sum - target < res - target 时
        • res = sum
      • 当 sum == target 时
        • 返回 sum 即为所求
      • 当 sum > target
        • 根据从小到大的排序方式,左右指针不能再增大,只有右指针能够缩小,进而缩小 sum 值
        • right--
      • 当 sum < target
        • 原理同上,只不过先从小的元素累加起
        • left++
/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var threeSumClosest = function(nums, target) {
    nums.sort((a,b) => a - b);
    let res = nums[0] + nums[1] + nums[2];
    let n = nums.length;
    for(let i = 0;i < n;i++){
        let left = i + 1;
        let right = n - 1;
        while(left < right){
            let sum = nums[i] + nums[left] + nums[right];
            if(Math.abs(res - target) > Math.abs(sum - target)){
                res = sum;
            }else if(sum > target){
                right--;
            }else if(sum < target){
                left++;
            }else if(sum === target){
                return res;
            }
        }
    }
    return res;
};

最后

曾梦想仗剑走天涯

看一看世界的繁华

年少的心总有些轻狂

终究不过是个普通人

无怨无悔我走我路

「前端刷题」No.16