三数之和

72 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第26天,点击查看活动详情

题目描述

给你一个包含 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
  • -105 <= nums[i] <= 105

思路

本题主要考察双指针算法。首先对数组进行排序,排序后选定第一个数 nums[i],再使用左右指针指向 nums[i]后面的两端,计算三个数的和 sum 判断是否满足为 0,满足则添加进结果集。如果 nums[i]大于 0,则三数之和必然无法等于 0,结束循环 。如果 nums[i] == nums[i-1],则说明该数字重复,会导致结果重复,所以应该跳过。

注意:

  • 当 sum == 0 时,nums[L] == nums[L+1] 则会导致结果重复,应该跳过,L ++
  • 当 sum == 0 时,nums[R] == nums[R-1] 则会导致结果重复,应该跳过,R --

代码

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> res;
        int length = nums.size();
        // 当数组中的元素小于3时,不可能构成3元组
        if(length < 3) return res;
        // 对数组进行排序
        sort(nums.begin(), nums.end());
        // 从前到后,先确定第一个数子,再通过双指针去找以第一个数作为基数的,三元组的所有可能情况
        for(int i = 0;i < length;i ++)
        {   
            // 当第一个数大于0时,由于是排序数组,后面所有的数都大于0,不可能找到满足条件的三元组
            if(nums[i] > 0) return res;
            // 当第一个数和下一个数重复时,找到的情况相同,需要跳过
            if(i > 0 && nums[i] == nums[i - 1]) continue;
            // 定义左右指针
            int left = i + 1, right = length - 1;
            while(left < right)
            {   
                // 当三数之和小于0时,移动左指针
                if(nums[i] + nums[left] + nums[right] < 0)
                {
                    left ++;
                }
                // 当三数之和大于0时,移动右指针
                else if(nums[i] + nums[left] + nums[right] > 0)
                {
                    right --;
                }
                else
                {
                    vector<int> ans;
                    // 把满足条件的三元组加入答案数组中
                    ans.push_back(nums[i]), ans.push_back(nums[left]), ans.push_back(nums[right]);
                    res.push_back(ans);
                    // 对left去重
                    while(left < right && nums[left] == nums[left + 1]) left ++;
                    // 对right去重
                    while(left < right && nums[right] == nums[right - 1]) right --;
                    left ++, right --;
                    
                    
                }
            }
        }
​
        return res;
    }
};