leetcode015三数之和

54 阅读2分钟

15. 三数之和

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。

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

示例 1:

输入: nums = [-1,0,1,2,-1,-4]
输出: [[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1][-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。

暴力解法(在leetcode中会超时) 这个暴力法是在 两数之和 的基础上加了一重循环,nums[i]相当于 两数之和 中的target

var threeSum = function (nums) {
  let resArr = []
  let targetArr = []
  for (let i = 0; i < nums.length; i++) {
    let target = nums[i]
    targetArr.push(target)
    let arr = []
    for (let j = i + 1; j < nums.length; j++) {
      if (arr.indexOf(0 - target - nums[j]) === -1) {
        arr.push(nums[j])
      } else {
        let temp = [target, 0 - target - nums[j], nums[j]]
        let strtemp = JSON.stringify(temp.sort())
        let isSame = false
        resArr.forEach(item => {
          if (JSON.stringify(item) === strtemp) isSame = true
        })

        if (!isSame) resArr.push(temp)
      }
    }
  }
  return resArr
}

优化之后的解法

先对数组进行排序,遍历数组,nums[i]为target,nums[i+1]及之后的数组中分别设置两个头尾指针,根据头尾相加值与target的大小,决定是移动左指针还是右指针 因为题目中答案中不可以包含重复的三元组的要求,所以需要跳过重复值

var threeSum = function (nums) {
  let res = []
  nums.sort((a, b) => a - b)
  let len = nums.length
  if (nums[0] > 0 || nums[len - 1] < 0) return res
  for (let i = 0; i < len; ++i) {
    // 跳过重复值
    if (i > 0 && nums[i] === nums[i - 1]) continue
    // 最左侧值为定值,右侧所有值进行两边推进计算
    let target = nums[i]
    let left = i + 1
    let right = len - 1
    while (left < right) {
      if (nums[left] + nums[right] + target === 0) {
        res.push([nums[i], nums[left], nums[right]])
        // 跳过重复值
        while (left + 1 < len && nums[left++] === nums[left]) { }
        while (right - 1 > 0 && nums[right--] === nums[right]) { }
      } else if (nums[left] + nums[right] + target > 0) {
        right--
      } else if (nums[left] + nums[right] + target < 0) {
        left++
      }
    }
  }
  return res
}