Skip to content
On this page

15-三数之和

标签:数组 双指针 排序

题目信息

题目地址15. 三数之和

题目内容:

javascript
给你一个整数数组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] 。
        注意,输出的顺序和三元组的顺序并不重要。

示例 2
    输入:nums = [0,1,1]
    输出:[]
    解释:唯一可能的三元组和不为 0

示例 3
    输入:nums = [0,0,0]
    输出:[[0,0,0]]
    解释:唯一可能的三元组和为 0
 
提示:
    3 <= nums.length <= 3000
    -105 <= nums[i] <= 105

题解

解法一

思路:

先对数组进行从小到大排序,如果数组开头的数字大于0或者数组结尾的数字小于0,则不可能存在三个数相加为0的情况,直接返回

遍历数组,获得当前遍历索引i,然后定义leftright指针,left指针指向i的下一位,right指针指向数组末尾

遍历过程中,要先对i指向的值去重,然后如果当前i位置的数字大于0,就直接返回res

然后计算ileftright指向的值的和sum

1、如果sum大于0,说明需要减小,将right指针向左移动一位

2、如果sum小于0,说明需要增加,将left指针向右移动一位

3、如果sum等于0,说明找到了一个满足条件的三元组,将这个三元组加入到res中,然后需要对leftright进行去重,去重结束后,需要将leftright分别移动一位

最后返回res

代码实现:

javascript
/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var threeSum = function(nums) {
    // 将数组从小到大排序
    nums.sort((a, b) => a - b)
    // 如果数组最小值大于0或者最大值小于0 直接返回
    const numsLen = nums.length
    if(nums[0] > 0 || nums[numsLen - 1] < 0) return []
    const res = [] // 结果
    for(let i = 0; i < numsLen; i++) {
        // 如果当前的数字是大于0的,那它之后的数字都是比它大的,肯定不可能相加为0,直接返回result
        if(nums[i] > 0) return res
        // 对i指向的值去重
        if(i > 0 && nums[i] === nums[i - 1]) {
            continue
        }
        // 定义left right指针 left 就是i的下一位 right
        let left = i + 1, right = numsLen - 1
        while(left < right) {
            // 计算三个数的和
            const sum = nums[i] + nums[left] + nums[right]
            if(sum > 0) { // 和大于0 的话 让right 向左移动,减少right指向的值
                right--
            }else if(sum < 0) { //和小于0的话,让left向右移动,增大left指向的值
                left++
            }else { // 和等于0记录三个数 并且开始对left和right指向的值去重
                res.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都要再走一步 这个很关键
                left++
                right--
            }
        }
    }
    return res
};