15.3Sum

Description

Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note:

The solution set must not contain duplicate triplets.

Example:

Given array nums = [-1, 0, 1, 2, -1, -4],

A solution set is:
[
  [-1, 0, 1],
  [-1, -1, 2]
]
题目传送门

一.题目理解

这是LeetCode的第15题,主要方法是双指针和数组。

题目要求给定含n个元素的数组,找出其中三个相加为0的元素,并把找到的所有情况返回。

二.题目解答

题目好理解,但是有一些细节值得注意。
  1. 找出所有的情况
  2. 返回的三元组不能重复

因为,我们需要思考的是:

  1. 如何对数据去重,防止三元组重复
  2. 如何快速的搜索到符合条件的三元组

1.set方法

类比第1题,这道题可以认为是随机给定一个值(三元组中第一个数),我们把它当作target值,然后再剩余数组中搜索有没有两数之和等于这个数的相反数。可以看到,这很像第1到题,但与第1题不同的是,答案不是唯一解,而且元素有重复的,因而这里不再适合使用unordered_map。

如何使考虑到的元素不重复,也就是在处理之前或处理之中把重复的数字筛选出去,我们立刻想到STL中set是不重复的,但是如果在搜索前过滤数据到set中,在搜索过程中还要进行某些重复的工作,效率并不高,那是不是能在筛选元素的过程中直接进行处理呢?答案是可以的。

下面是代码:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {

        vector<vector<int>> ans;
        unordered_set<int> s;
        sort(nums.begin(),nums.end());

        for(int i = 0; i < nums.size(); i++) {
           //去重1
            if(i != 0 && nums[i - 1] == nums[i])
                continue;

            s.clear();
            for(int j = i + 1; j < nums.size(); j++) {
                if(s.count(-nums[i] - nums[j])) {
                    ans.push_back({nums[i],nums[j],-nums[i] - nums[j]});
                  //去重2
                    while(nums[j + 1] == nums[j] && j + 1 < nums.size())
                        j++;
                }
                s.insert(nums[j]);
            }

        }

        return ans;

    }
};

可以看到,我们去重操作用了两步,第一步是为了防止处理相同的target值,这是因为每次处理不同的target值的时候,符合条件的已经全部找出,下一次如果target值相同,得到的解必然重复);第二步是为了防止出现相同的三元组解,这是因为前两个元素固定了,最后一个元素必然唯一。

2.双指针方法

首先这是个数组,其次要求解的问题与数组元素的值相关,而且对重复值有要求,因为我们可以对其进行预处理以减少操作,这里所做的预处理就是排序。

经过预处理之后,数组变得”良好”,终止条件也比较明确,如果第一个元素就已经是正数,后面的数字一定全部是正数,这样它们的和肯定不是0;其次,再处理元素时,我们可以方便的把要处理的元素和已处理的元素作比较,如果相同,我们也可以跳过,这样对于冗余元素的数组,我们可以大大提高处理速度。

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {

        vector<vector<int>> ret;
        vector<int> vec;
        int target;
        int front,rear;

        sort(nums.begin(),nums.end());

        for(int i = 0; i < nums.size(); i++) {

            target = -nums[i];

            if(target < 0)
                break;
            
            if(i != 0 && nums[i] == nums[i - 1])
                continue;
            
            front = i + 1;
            rear = nums.size() - 1;
            while(front < rear) {
                int sum = nums[front] + nums[rear];
                if(sum < target)
                    front++;
                else if(sum > target)
                    rear--;
                else {
                    vector<int>().swap(vec);
                    vec.push_back(nums[i]);
                    vec.push_back(nums[front]);
                    vec.push_back(nums[rear]);
                    ret.push_back(vec);

                    //去重
                    while(front < rear && nums[front] == vec[1])
                        front++;
                    while(front < rear && nums[rear] == vec[2])
                        rear--;
                }
            }       
        }
        return ret;
    }
};

 












原文地址:https://www.cnblogs.com/ovs98/p/9839571.html