【我的力扣战纪】双指针-15-三数之和

274 阅读2分钟

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

她的客气, 让我觉得很生疏很有距离感,让我觉得 ,我多努力都走不到她的身边 。我很清楚我根本没有能让她喜欢的本事, 所以我一直在鼓励自己, 把自己的价值提一提。可能最终无济于事, 但也至少不会让她反感

原题链接:15-三数之和

给你一个包含 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 = [0,1,1]
输出: []

示例 3:

输入: nums = [0,0,0]
输出: [[0,0,0]]

提示:

  • 3 <= nums.length <= 3000
  • -10^5 <= nums[i] <= 10^5

思路

  • 先对数组进行排序,保证首项最小,尾项最大
  • 再对数组进行遍历,使用左右指针指向 nums[i]的两端,然后计算三个数的和判断是否为0,满足则添加进返回数组中
  • 接下来如何移动左右指针呢, 如果nums[i] + 左指针 + 右指针 > 0 就说明 此时三数之和大了,因为数组是排序后了,所以右指针的下标就应该向左移动,这样才能让三数之和小一些。如果 nums[i] + 左指针 + 右指针 < 0 说明 此时 三数之和小了,左指针 就向右移动,才能让三数之和大一些,直到左右指针相遇为止中断循环
  • 对i、左右指针做去重处理,避免结果重复

Code

const threeSum = nums => {
    const len = nums.length
    const res = []
    // 双指针法必须排序
    nums.sort((a, b) => a - b)
    if (nums[0] <= 0 && nums[len - 1] >= 0) {
        for (let i = 0; i < len - 2;) {
            let left = i + 1, right = len - 1;
            do {
                if (left >= right || nums[i] * nums[right] > 0) break;
                let sum = nums[i] + nums[left] + nums[right]
                if (sum === 0) {
                    res.push([nums[i], nums[left], nums[right]])
                }
                 if (sum <= 0) {
                    while (left < right && nums[left] === nums[++left]); //左指针去重 一直找到不相同的那个坐标
            }
                else {
                    while (left < right && nums[right] === nums[--right]); //右指针去重 一直找到不相同的那个坐标
            }
            }
            while (left < right);
            while(nums[i]===nums[++i]); // 对i的去重 若当前这一项和下一项相等则跳过
        }
    }
    return res
}

复杂度分析

  • 时间复杂度:O(n^2)
  • 空间复杂度:O(1)