15. 3Sum

来源:互联网 发布:tcl网络电视怎么打开 编辑:程序博客网 时间:2024/05/18 06:28

Given an array S of n integers, are there elements abc in S 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.

For example, given array S = [-1, 0, 1, 2, -1, -4],A solution set is:[  [-1, 0, 1],  [-1, -1, 2]]

Subscribe to see which companies asked this question.

题目翻译:对给定的任意n元数组,找出其中三元相加为0的组合,如果有重复的组合,需要剔除。

实际上,我们看输出的结果是用一个二维的数组输出,每行三元,三元相加之和为0;

而且这些输出的结果是升序排列,这意味着我们要先给数组排个序;

排序用快排的时间复杂度是nlogn,说到时间复杂度是因为该题其实有时间限制,一开始我用的是三重循环遍历所有可能的组合,时间复杂度为n^3;

而且这样的做法在调试时会等待过久,效率太低;

首先考虑边界条件,如果数组的元素个数少于三个,则返回{};

这里我用的是双指针法:

第一:从坐标i=0的元素遍历到坐标i=nums.size()-3的元素,即倒数第三个,每一次遍历都是从该元素后面的元素中寻找可与之配对的另外两个元素;

这样做的原因是因为:

中间任意第k个元素,0<=k<=nums.size()-3,若在该元素前面存在至少一个元素,坐标为j,0<=j<k可以与之形成配对,那么在遍历到第j个元素的时候,肯定已经找到了相同的配对,因为数组是已经排好序(升序排列),而且不允许有重复的三元配对,所以每一组三元配对唯一,因此后面遍历到第j个元素若和前面的元素有产生配对,则在遍历前面的元素时已经产生相同配对,故而每次遍历到第i个元素时,只需要找到它后面的元素中可能存在的配对即可;

由于是三元配对,所以遍历到倒数第三个元素,后面的两个元素已经不能产生三元配对了;

第二:双指针,每一次遍历,初始化令front=i+1,rear=nums.size()-1;

检查nums[i]+nums[front]+nums[rear]的值跟0的对比,比0大则相当于固定了指针rear,这是因为数组是升序排列,此时的front是剩余可与第i个元素和第rear个元素配对的元素中最小的那个,前面讨论了不可能存在还有在front前面的元素组成配对的情况,那么现在就是也不存在还有在front后面的元素组成配对的情况,因此,组合nums[i]+nums[rear]在所有剩余元素中找不到可匹配的元素,所以rear--;

同理,比0小则相当于固定了指针front,由于数组升序排列,比目前的nums[rear]更小的明显不符合,而比它大的元素已经与nums[i]配对过,因此此时front++;

若是等于0,则产生组合,此时把组合插入到要输出的二维数组中去,res.push_back({nums[i]},nums[front],nums[rear]),

显然,此时单一的front++或者rear--都不可能满足,所以同时front++,rear--;

然后进行重复检测,若是nums[front]==nums[front-1],则继续加到不等为止;

rear同理,nums[rear]==nums[]rear+1],则继续减到不等为止;

找完对应与nums[i]的所有配对之后,检测i的重复;

i++;然后nums[i]==nums[i-1],则继续i++直到不等为止;

以下为代码示例:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        if(nums.size() <=2) return {};
        vector<vector<int> > res;
        //vector<int> triplet(3, 0);
       std::sort(nums.begin(), nums.end());
        int i,target,temp,front,rear;
        for(i=0;i<nums.size()-2;i++){
            front=i+1;
            rear=nums.size()-1;
            
            target=-nums[i];
            while(front<rear){
                temp=nums[front]+nums[rear];
               if(temp==target){
                    
                    
                    res.push_back({nums[i],nums[front],nums[rear]});
                    
                    while(front<rear&&nums[front]==nums[front+1]){
                        front++;
                    }
                    while(front<rear&&nums[rear]==nums[rear-1]){
                        rear--;
                    }
                    front++;
                    rear--;
                    
                }
                else if(temp>target)
                rear--;
                else
                front++;
            }
            
            while(i<nums.size()-2&&nums[i]==nums[i+1]){
                i++;
            }
        }
        return res;
        


    
        
    }
};





0 0
原创粉丝点击