算法之三数之和

224 阅读1分钟

「这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战」。

又是算法时间,这道题太折磨我了,改到最后和小伙伴的题解一样了!还是错的,我要崩溃了呀!最后一个一个debugger,才发现问题所在,具体请看下文。

题目描述

给你一个包含 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的任意排序元组,如果是升序,就会大大减少重复三元组的数量;如果用三重for循环暴力拆解,哎,不说了,想想就头疼~

所以,这道题的解题方案为:排序 + 双指针

代码

    /**
    * @param {number[]} nums
    * @return {number[][]}
    */
    var threeSum = function (nums) {
      //判断是否符合三数之和情况
      let result = []
      if (nums == null || nums.length < 3) return result
      //升序排序
      nums.sort((a, b) => a - b) 
      for (let i = 0; i < nums.length; i++) {
        //如果nums[i]大于0了,不存在三数之和为0的情况,直接跳出循环
        if (nums[i] > 0) break
        //这里就是那个坑,主要目的是去重
        //注意: 比较的时候,一定是nums[i] 与 nums[i-1] 去比较,不然就会有漏失
        if (i > 0 && nums[i] == nums[i - 1]) continue
        //定义左指针和右指针
        let left = i + 1;
        let right = nums.length - 1;
        //指针结束条件
        while (left < right) {
          if (nums[i] + nums[left] + nums[right] == 0) {
            result.push([nums[i], nums[left], nums[right]])
            //刚开始我没想到,这里也需要去重
            while (left < right && nums[left] == nums[left + 1]) left++
            while (left < right && nums[right] == nums[right - 1]) right--
            left++
            right--
          } else if (nums[i] + nums[left] + nums[right] > 0) {
            right--;
          } else if (nums[i] + nums[left] + nums[right] < 0) {
            left++;
          }
        }
      }
      return result
    };