【算法实战之力扣刷题】 三数之和

45 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第8天,点击查看活动详情

题目描述

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

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

示例:

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

输出:[[-1,-1,2],[-1,0,1]]

输入:nums = [0]

输出:[]

解题思路

此题可以依据两数之和的暴力枚举法,进行三层遍历,取和为0的三元组,并在最后去重,但是不够优雅,直接跳过(ps:太麻烦了! doge)

排序 + 双指针解法:

外层循环:指针 i 遍历数组。 内层循环:用双指针,去寻找满足三数之和为0的元素

  1. 首先判断数组长度是否小于3,如果为真,直接返回一个空数组

  2. 对数组进行排序,便于跳过重复元素,如果当前元素和前一个元素相同直接跳过

  3. 因为需要同时找三个数,所以采取固定一个数,同时用双指针来查找另外两个数的方式。循环数组nums,假如当前循环到了i索引,则定义两个指针L = i+1,和R = nums.length-1, 计算这三个数(nums[i],nums[L],nums[R])的和 sum,判断和 sum 是否满足为 0,满足则添加进结果集

    sum = nums[i] + nums[L] + nums[R]

    a. 如果sum小于0,说明左指针指向的值小,需要向右移动左指针L++;

    b. 如果sum大于0,说明右指针指向的值大,则向左移动右指针R--;

    c. 如果sum等于0,则正好找到了这3个数,然后在尝试L++,R--,继续寻找中间是否有三个数之和等于0

    注意: 在循环的过程中遇见相同的三个数需要去重

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var threeSum = function(nums) {
  let ans = [];
  const len = nums.length;
  if(nums == null || len < 3) return ans; //数组的长度需要大于3
  nums.sort((a,b) => a - b); //数组排序:升序
  for(let i = 0; i < len; i++){
    if(nums[i] > 0) break; // 如果当前数字大于0,则三数之和一定大于0,所以结束循环
    if(i > 0 && nums[i] == nums[i-1]) continue; // nums[i] == nums[i-1],则说明该数字重复,会导致结果重复,所以应该跳过( 去重)
      let L = i+1;
      let R = len-1;
      while(L < R){
          const sum = nums[i] + nums[L] + nums[R];
          if(sum == 0){
              ans.push([nums[i],nums[L],nums[R]]);
              while (nums[L] == nums[L+1]) L++; // 去重
              while (nums[R] == nums[R-1]) R--; // 去重
              L++;
              R--;
          }
          else if (sum < 0) L++;
          else if (sum > 0) R--;
      }
  }
  return ans;  
};

image.png