# 三数之和

# 一、题目描述

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

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

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

示例 2:
输入:nums = []
输出:[]

示例 3:
输入:nums = [0]
输出:[]
1
2
3
4
5
6
7
8
9
10
11

# 二、解题思路

本体难点在于如何去除重复解。

  1. 特殊判断,length < 3,返回 []
  2. 数组排序(注意数组sort方法的坑...)
  3. 遍历数组:
  • nums[i] > 0:因为已经排好序,所以后面不可能有三个数加和等于 0 ,直接返回结果。
  • 对于重复元素:跳过,避免出现重复解
  • 令左指针 L = i + 1,右指针 R = n - 1,当 L < R 时,执行循环:
    • nums[i] + nums[L] + num[R] === 0 时,执行循环,判断左界和右界是否和下一位置重复,去除重复解。并同时将 L,R移到下一位置,寻找新的解。
    • 若和大于0,说明 nums[R] 太大,R左移
    • 若和小于0,说明 nums[L] 太小,L右移
/**
 * @param {number[]} nums
 * @return {number[][]}
 */
 var threeSum = function(nums) {
  //  特殊情况处理
  if (nums.length < 3) return [];

  // 排序
  nums.sort((a,b) => a - b); 

  // 遍历
  let results = [];
  for (let i = 0; i < nums.length; i++) {
    // nums[i] > 0,说明后面不可能有三数之和等于0,直接返回结果
    if (nums[i] > 0) return results;

    // 对于重复元素:跳过,避免出现重复解
    if (i > 0 && nums[i] === nums[i - 1]) continue;

    let left = i + 1; // 左指针
    let right = nums.length - 1; // 右指针
    let sum;

    while(left < right) {
      sum = nums[i] + nums[left] + nums[right]; // 三数之和
      if (sum > 0) { // 和大于0,说明 right 太大,右指针左移
        right--;
      } else if (sum < 0) { // 和小于0,说明 left 太小,左指针右移
        left++;
      } else {
        results.push([nums[i],nums[left],nums[right]]); // 得到解,左右指针同时移动
        left++;
        right--;

        while (nums[left] === nums[left-1]) left++; // 跳过重复数字
        while (nums[right] === nums[right+1]) right--; // 跳过重复数字
      }
    }
  }

  return results;
};

console.log(threeSum([-1,0,1,2,-1,-4]));

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
上次更新: 1/5/2022, 9:25:14 AM