算法【中等-15.三数之和】

2 阅读3分钟

Hello,大家好,我是disguiseFish,我已经摆烂很长一段时间啦,摆烂的日子过得快乐又飞快~不知不觉都一年多了!!

最近在卷算法,但其实我的逻辑思维能力偏弱以及我之前就没有刷过算法!!所以我决定,每天写一点算法提升自己的逻辑思维!接下来我会从简入深的顺序来卷算法,同时会把看过的算法记录在这个平台~ 共勉!!!

15.三数之和

给你一个整数数组nums,判断是否存在三元组[nums[i], nums[j], nums[k]] 满足i != j、i != k且j!= k,同时还满足nums[i] + nums[j] + nums[k] == 0。请你返回所有和为0且不重复的三元组。 注意:答案中不可以包含重复的三元组。

示例 1:

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

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

解释:

nums[0] + nums[1] + nums[2] = (-1) +0 + 1= 0

nums[1] + nums[2] + nums[4] =0 + 1 +(-1) = 0

nums[0] + nums[3] + nums[4] = (-1) + 2+(-1) = 0

不同的三元组是[-1,0,1] 和 [-1,-1,2]

注意,输出的顺序和三元组的顺序并不重要。但不能重复

解决方案

思路:先给数组从小到大排序,然后利用双指针往中间移动,分别找出sum为0的搭配,然后对特殊情况(当有重复值的时候)做处理

特殊情况的处理思路1,2,3:

image.png

总体思路:

image.png

var threeSum = function (nums) {
    let res = []
    nums.sort((a, b) => a - b)
    for (let index = 0; index < nums.length; index++) {
        // 当当前循环最小值都大于0了  那直接返回res
        if (nums[index] > 0) return res
        let Left = index + 1
        let Right = nums.length - 1
        //  当 当前值 不是第一个数 且 当前值和上一个值一样的时候 就不用循环了 直接进入下一个循环
        if (index > 0 && nums[index] === nums[index - 1]) {
            continue
        }
            // 1.当左指针小于右指针 则循环指针移动
            while (Left < Right) {
                // 当三者相加为0 把值push进
                if (nums[index] + nums[Left] + nums[Right] === 0) {
                    res.push([nums[index], nums[Left], nums[Right]])
                    // 左指针右移 右指针左移 两个指针往中间移动  只要不重复就不跳循环
                    Left += 1
                    Right -= 1
                    while (Left < Right && nums[Left] === nums[Left - 1]) {
                        // 判断 左指针移动后和之前的值是否一样 如果是一样的话继续移动
                        // 为了避免值一样 输出一样的值
                        Left += 1
                    }
                    while (Left < Right && nums[Right] === nums[Right + 1]) {
                        // 判断 右指针移动后和之前的值是否一样 如果是一样的话继续移动
                        // 为了避免值一样 输出一样的值
                        Right -= 1
                    }
                }
                // 2.当三者相加小于0 说明总和可以再大一点 这时可以左指针往右移动加大
                if (nums[index] + nums[Left] + nums[Right] < 0) {
                    Left += 1
                    while (Left < Right && nums[Left] === nums[Left - 1]) {
                        // 判断 左指针移动后和之前的值是否一样 如果是一样的话继续移动
                        // 为了避免值一样 输出一样的值
                        Left += 1
                    }
                }
                // 3.当三者相加大于0 说明总和可以再小一点 这时可以右指针往左移动减小
                if (nums[index] + nums[Left] + nums[Right] > 0) {
                    Right -= 1
                    while (Left < Right && nums[Right] === nums[Right + 1]) {
                        // 判断 右指针移动后和之前的值是否一样 如果是一样的话继续移动
                        // 为了避免值一样 输出一样的值
                        Right -= 1
                    }
                }

            }

    }
    return res
}