LeetCode:15 三数之和 双指针与去重技巧

题目描述

给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。

注意:答案中不可以包含重复的三元组。

示例:

给定数组 nums =

[-1, 0, 1, 2, -1, -4]

满足要求的三元组集合为:

[
  [-1, 0, 1],
  [-1, -1, 2]
]

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/3sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

在一个有序区间内寻找两个加和等于定值的数,可以用尺取法(双指针),即左右指针加和大,右指针左移,加和小,左指针右移,复杂度为O(n),对于三个数,我们只需要

  • 穷举第一个数字number1
  • 问题变成在这个数字后面的区间找两数之和=target-number1
  • 在这个数字后面的区间用双指针找到给定的目标值

注意:
因为双指针要求数组有序,我们必须将数组排序

去重:
排序之后的数组是有序的,意味着相同的元素都连在一起,可是我们不希望选取相同的元素

  • 对于穷举第一个数字,我们令它不等于它的前一个数字即可做到去重
  • 对于双指针找第二第三,一旦找到两个合法的数n2, n3,左指针一直向右,直到找到一个不同于n2的数,右指针一直向左,直到找到一个不同于n3的数

注意去重的时候,要判断边界情况,否则容易导致越界

代码

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums)
    {
        vector<vector<int> > ans;
        sort(nums.begin(), nums.end());
        for(int i=0; i<nums.size(); i++)
        {
        	// 第一个数去重
            if(i==0 || nums[i]!=nums[i-1])
            {
                int l = i+1;
                int r = nums.size()-1;
                while(l<r)
                {
                    if(nums[i]+nums[l]+nums[r]>0)
                    {
                        r--; continue;
                    }
                    if(nums[i]+nums[l]+nums[r]<0)
                    {
                        l++; continue;
                    }
                    if(nums[i]+nums[l]+nums[r]==0)
                        ans.push_back(vector<int>{nums[i], nums[l], nums[r]});
                    // 第二三个数去重
                    while(l+1<nums.size() && nums[l]==nums[l+1])
                        l++;
                    while(0<=r-1 && nums[r]==nums[r-1])
                        r--;
                    l++; r--;
                }
            }
        }
        return ans;
    }
};
发布了171 篇原创文章 · 获赞 7 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44176696/article/details/104461317