前端算法第一六七弹-三数之和

115 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第23天,点击查看活动详情

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

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

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]

示例 2:

输入:nums = []
输出:[]

示例 3:

输入:nums = [0]
输出:[]

提示:

  • 0 <= nums.length <= 3000
  • 105 <= nums[i] <= 105

排序 + 双指针

  • 使用双指针首先我们要对数组进行排序 nums.sort()
  • 定义一个res数组存放三元组
  • 写一个for循环,循环当前遍历到的数即为我们已经固定的数(因为双指针只能指向两个数,所以我们还需固定一个数)
  • 定义两个指针 j(指向当前遍历到的元素的下一个元素)、k(指向数组末尾元素),边界为 j < k
  • 令三数相加
  • 若相加大于0 则说明nums[k]大了,k指针向左移 k--
  • 反之则说明nums[j]小了, j指针右移 j++
  • 若等于0 则说明该组三元组是一个解
  • 注:在这些三元组中可能会存在重复的解,我们还需把重复的解排除出去
  • 分别在移动指针前,移动指针时,和移动指针后对重复的解进行排除
  • 在移动指针前,若前一个被遍历的元素与当前遍历到的元素相等则说明这种情况已经出现过不需要再寻找一次了(nums[i] === nums[i-1])
  • 在移动指针时,若三数之和大于0,使用while循环检查当前nums[k]与之前的nums[k+1]是否相等,若相等则继续递减,直至不相等为止
  • 若三数之和小于0,用while循环检查nums[j]与之前的nums[j - 1]是否相等,若相等则继续递增,直至不相等位置,同时 j < k这个条件不能遗漏
  • 若三数之和等于0,此时j++ k--,我们需要分别对上述两种情况都进行检查
  • 最终将得到的结果使用push方法放入res数组中
/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var threeSum = function(nums) {
  let ans = []
  const n = nums.length
  nums.sort((a, b) => a - b)
  for (let i = 0; i < n && nums[i] <= 0; i++) {
    const num = nums[i];
    if (nums[i] == nums[i - 1]) continue
    let l = i + 1, r = n - 1
    while (l < r) {
      let sum = num + nums[l] + nums[r]
      if (sum > 0) r--
      else if (sum < 0) l++
      else {
        ans.push([num, nums[l], nums[r]])
        l++, r--
        while (l < r && nums[l] == nums[l - 1]) l++
        while (l < r && nums[r] == nums[r + 1]) r--
      }
    } 
  }
  return ans
};