【力扣刷题记 15】——《三数之和》

169 阅读1分钟

Offer 驾到,掘友接招!我正在参与 2022 春招打卡活动,点击查看活动详情

一、题目描述:

  1. 三数之和-难度中等

给你一个包含 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 -10^5 <= nums[i] <= 10^5

二、题目和思路分析:

这道题看起来一点也不难,不就是三数之和的情况嘛,还不是轻轻松松,我怎么也没想到自己会从九点多奋战到现在将近三小时才做出来。

最开始我是这么想的:

和为0,则应该有正数,有负数,将数组从小到大进行排序。然后以0为界限,分左右两部分,开始执行下面操作:

  1. 取左侧最小的两个数字之和的绝对值,右侧大于这个绝对值的数可以删除掉,因为不会有能和它相加为0的两个数。

  2. 取右侧最大的两个数字之和的相反数,左侧小于这个绝对值的数可以删除掉,因为不会有能和它相加为0的两个数。

  3. 如果含0,则判断是否存在绝对值相同的正负数,得到答案的一部分,再取不含0的方法得到答案的另一部分。

  4. 如果不含0,判断左侧任意两数相加的绝对值,是否对应右边某数。再判断右侧任意两数相加的绝对值,是否对应左边某数。

写代码的过程中,我发现考虑不周到,又加了条件:

多个重复数字应单独取出对应的三元组后进行去重处理,即:

非0数字重复次数最多应为2次,0重复次数最多应为3,并且取出000之后去重为0。

就这么在这种条件下,我写的坎坎坷坷,代码加上空行写了一百多行。。。还是一直不对。

眼瞅着马上两个小时了,好像就要成功,但成功又好像总差了一步,于是我想,能不能转换思路呢?

三数相加考虑的情况有点复杂,那么两数相加呢?好像简单了很多啊!!!

设置当前循环的数字为基准数字,然后前面的算法题经常用到双指针,首尾同时遍历,也就是基准数加上双指针进行遍历循环,这不是很容易嘛!

又是一番细节的修修改改不懈努力,终于搞定啦!

三、代码:

代码实现如下:

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var threeSum = function(nums) {
    if(nums == null || length < 3){
        return []
    }
    let arr = [] // 声明空数组
    nums.sort((a, b) => a - b) // 数组从小到大进行排序
    let length = nums.length
    for (let i = 0; i < length ; i++) {
        if(nums[i] > 0){ // 如果最小数字大于0,那么和也一定大于0
            break
        }
        if(i > 0 && nums[i] == nums[i-1]){ // 当前数字与上个数字相同,说明已经循环过了,跳出本次循环
            continue
        }
        let left = i+1
        let right = length-1
        while(left < right){
            const sum = nums[i] + nums[left] + nums[right]
            if(sum == 0){
                arr.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 (sum < 0){
                left++
            }
            else if (sum > 0){
                right--
            }
        }
    }        
    return arr
}

四、总结:

这道题看起来一点也不难,实际上我在这道题却花费了整个晚上。思路错了之后怎么也做不对。

即使是错误的思路,思路转为代码也还是太慢了,其中又因为粗心或者考虑不周,情况兼顾不到,逻辑不完善,修修改改调试最费时间了。

好久没熬夜这么晚了, 加油吧!

image.png