leetcode 三数之和

2020/05/05 two-pointers algorithm

和之前的最接近三数之和的解法差不多,多了重复值的判断

最接近三数之和

描述

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。

注意:答案中不可以包含重复的三元组。 示例:

给定数组 nums = [-1, 0, 1, 2, -1, -4],

满足要求的三元组集合为:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

解法 双指针

使用嵌套三层的循环也可以解出来,但是太耗时了。
还是一样要先排序数组,保持升序。 后两层循环可以优化为双指针,当结果值大时,右边的指针向左移,当结果值小时,左边的指针向右移。
去除重复值可以看已经满足结果的下一个循环的值是不是一样的,一样的就不循环,也就不会有重复的结果了。

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var threeSum = function (nums) {
  nums = nums.sort((a, b) => a - b)
  const res = []
  let res1, length = nums.length
  if (length < 3) {
    return []
  }
  for (let i = 0; i < length - 2; i++) {
    // 当前循环的值的下一个值、数组的最后一个值
    let j = i + 1, k = length - 1
    // 跳过重复值
    if (nums[i] === nums[i - 1]) {
      continue
    }
    while (j < k) {
      res1 = nums[i] + nums[j] + nums[k]
      if (nums[i] / nums[k] > 0) {
        break
      }
      if (res1 === 0) {
        res.push([nums[i], nums[j], nums[k]])
        while (nums[j] === nums[++j]) { } // 重复值跳过
      } else if (res1 < 0) {
        while (nums[j] === nums[++j]) { } // 重复值跳过
      } else if (res1 > 0) {
        while (nums[k] === nums[--k]) { } // 重复值跳过
      }
    }
  }
  return res
};

四数之和

如果说要解四数之和,那就只用在外面再加一层循环。让里面判断的目标值改为目标值减去一个层循环值。

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[][]}
 */ 
var fourSum = function (nums, target) {
  nums = nums.sort((a, b) => a - b)
  const res = []
  let res1, length = nums.length
  if (length < 4) {
    return []
  }
  for (let g = 0; g < length - 3; g++) {
    // 跳过重复值
    if (nums[g] === nums[g - 1]) {
      continue
    }
    // 如果接下来的最小的和大于目标值,退出
    if (nums[g] + nums[g + 1] + nums[g + 2] + nums[g + 3] > target)
      break;
    // 如果接下来最大的和小于目标值,下一轮循环
    if (nums[g] + nums[length - 1] + nums[length - 2] + nums[length - 3] < target)
      continue;
    const ans = target - nums[g]
    // 三数之和
    for (let i = g + 1; i < length - 2; i++) {
      let j = i + 1, k = length - 1
      if (i > g + 1 && nums[i] === nums[i - 1]) {
        continue
      }
      while (j < k) {
        res1 = nums[i] + nums[j] + nums[k]
        if (res1 === ans) {
          res.push([nums[g], nums[i], nums[j], nums[k]])
          while (nums[j] === nums[++j]) { } // 重复值跳过
        } else if (res1 < ans) {
          while (nums[j] === nums[++j]) { } // 重复值跳过
        } else if (res1 > ans) {
          while (nums[k] === nums[--k]) { } // 重复值跳过
        }
      }
    }
  }
  return res
};

Search

    Table of Contents