3Sum, 3Sum Closest, 4 Sum

来源:互联网 发布:中国税务网络大学门 编辑:程序博客网 时间:2024/03/29 01:45
Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.Note:Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c)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)

暴力拆解的方法对数组进行遍历可以找到所有的。但尝试之后发现,去重是个很麻烦的事,重复的结果很难筛掉。
解决此题,首先要对数组进行排序。然后固定一个数,用两个下边从数组的两端进行遍历。减小算法复杂度。同时,还要从以下几个方面减小算法运行时间。
(1)原数组不够3个值返回空。
(2)固定一个值。遍历的下标范围从0到nums.size()-2,数组已排序,所以要满足nums[i]<=0。
(3)对于同一个固定值。要考虑多解的情况。我们用两个循环来处理。
(4)不满足条件则让左右下标向中间移动。

class Solution {public:    vector<vector<int>> threeSum(vector<int>& nums) {        vector<vector<int>> result;        int a=0,b=0,c=0;        sort( nums.begin() , nums.end() );        if(nums.size()<3)            return result;        for(int i=0;i<nums.size()-2 && nums[i]<=0;i++){            int l=i+1;            int r=nums.size()-1;            int sum=0;            if(i>0 && nums[i]==nums[i-1])                continue;            while(l<r){                sum=nums[i]+nums[l]+nums[r];                if(sum==0){                    vector<int> n;                    n.push_back(nums[i]);                    n.push_back(nums[l]);                    n.push_back(nums[r]);                    result.push_back(n);                    //处理同一个固定值多解的情况,同时可以省略不必要的比较                    while (++l < r  && nums[l-1] == nums[l]);                      while (--r > l && nums[r+1] == nums[r]);                  }                else if(sum<0)                    l++;                else if(sum>0)                    r--;            }        }        return result;    }};
Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target. Return the sum of the three integers. You may assume that each input would have exactly one solution.For example, given array S = {-1 2 1 -4}, and target = 1.The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).

这个问题的考虑方法和3Sum一样。还是对数组进行排序。固定一个值,然后从数组的两端取值逼近。不同之处在于,我们要找的是距离target最近的值,因此不用再记录每次的结果,只需要保留最近的值就可以了。当sum==target时,已经是最近的结果,直接返回即可。编码过程中,有一个问题是需要注意的,就是sum的初始取值。由于target未知,不能随意给sum赋一个常数,因为可能存在初始的sum就跟target相等的情况,造成算法得出错误的结果。所以。我给sum赋的初值是while循环第一次运行时tmp的值。这样以来就能保证算法的正确运行。

class Solution {public:    int threeSumClosest(vector<int>& nums, int target) {        sort(nums.begin(),nums.end());        int sum=nums[0]+nums[1]+nums[nums.size()-1];        int tmp=0;        for(int i=0;i<nums.size()-1;i++){            int l=i+1;            int r=nums.size()-1;            while(l<r){                tmp=nums[i]+nums[l]+nums[r];                if(tmp==target)                    return tmp;                else if(tmp>target){                    if(abs(sum-target)>abs(tmp-target))                        sum=tmp;                    r--;                }                else if(tmp<target){                    if(abs(sum-target)>abs(tmp-target))                        sum=tmp;                    l++;                }            }        }        return sum;    }};
Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.Note:Elements in a quadruplet (a,b,c,d) must be in non-descending order. (ie, a ≤ b ≤ c ≤ d)The solution set must not contain duplicate quadruplets.For example, given array S = {1 0 -1 0 -2 2}, and target = 0.A solution set is:(-1,  0, 0, 1)(-2, -1, 1, 2)(-2,  0, 0, 2)

4 Sum的问题,本来考虑就是在3 Sum的基础上多一层循环,固定两个数,然后从数组两头开始检索。但在实际测试中,有个问题实在头疼,那就是去重!!!加一层循环固定两个数,很难保证这两个数的组合不会出现重复。期间试了很多方法,包括设置i和j需要跳过的情况,以及与前一个插入的数组比较的策略,都不能完全保证重复数字的出现。然后又尝试外层固定的两个数也采用从数组两端向中间压缩的策略。代码重复度很大,而且这种方法会反过来缺少一些情况。所以,最后还是采用了在结果中去重,重新排序result,并用unique()函数去重,通过测试,代码如下:

class Solution {public:    vector<vector<int>> fourSum(vector<int>& nums, int target) {        sort(nums.begin(),nums.end());        vector<vector<int>> result;        if(nums.size()<4)            return result;        if(nums.size()==4){            if(nums[0]+nums[1]+nums[2]+nums[3]==target)                result.push_back(nums);            return result;        }        for(int i=0;i<nums.size()-3;i++){            for(int j=i+1;j<nums.size()-2;j++){                int l=j+1;                int r=nums.size()-1;                while(l<r){                    int sum=nums[i]+nums[j]+nums[l]+nums[r];                    if(sum==target){                        vector<int> tmp;                        tmp.push_back(nums[i]);                        tmp.push_back(nums[j]);                        tmp.push_back(nums[l]);                        tmp.push_back(nums[r]);                        result.push_back(tmp);                        while(++l<r && nums[l]==nums[l-1]);                        while(l<--r && nums[r]==nums[r+1]);                    }                    else if(sum<target)                        l++;                    else if(sum>target)                        r--;                }            }        }        sort(result.begin(),result.end());        result.erase( unique( result.begin(), result.end() ), result.end());        return result;    }};
0 0