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;
}
};