1. 3Sum
【题目】
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)
【解析】
K Sum问题是一个系列,博客 http://tech-wonderland.net/blog/summary-of-ksum-problems.html 总结得比较完整,有兴趣可以去看。
排序之后,我们就可以对数组用两个指针分别从前后两端向中间扫描了,如果是 2Sum,我们找到两个指针之和为target就OK了,那 3Sum 类似,我们可以先固定一个数,然后找另外两个数之和为第一个数的相反数就可以了。
代码不难,先看了再说。
class 3Sum{
public:
void twoSum(vector<vector<int>> &ret, vector<int> &nums, int begin, int target)
{
int l=begin;
int r=nums.size()-1;
while(l<r)//分别从前面和后面向中间走,从而保证最后产生的数据集一定是从小到大排序的
{
if(nums[l]+nums[r]+target==0)
{
vector<int> line;
line.push_back(target);
line.push_back(nums[l]);
line.push_back(nums[r]);
ret.push_back(line);
while(l<r && nums[l]==nums[l+1]) l++;//去重
while(l<r && nums[r]==nums[r-1]) r--;<span style="font-family: Arial;">//去重</span>
l++;
r--;
}
else if(nums[l]+nums[r]+target<0)
l++;
else
r--;
}
}
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> ret;
if(nums.size()<=2)
return ret;
int target;
sort(nums.begin(), nums.end());
twoSum(ret, nums, 1, nums[0]);
for(int i=1; i<nums.size()-2; i++)//注意,这里需要保证后面的数据至少有两个才可以进行下面的操作
{
if(nums[i]>0)
break;
if(nums[i]==nums[i-1])
continue;
else
twoSum(ret, nums, i+1, nums[i]);
}
return ret;
}
};
注意,对于 num[i],寻找另外两个数时,只要从 i+1 开始找就可以了。
这种写法,可以避免结果集中有重复,因为数组时排好序的,所以当一个数被放到结果集中的时候,其后面和它相等的直接被跳过。
2. 3Sum closet
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).
class 3SumCloset{
public:
int towSumCloset(vector<int> & nums, int begin, int curData, int target)
{
int l=begin;
int r=nums.size()-1;
int closet=nums[l]+nums[r]+curData;
while(l<r)
{
int tmp=nums[l]+nums[r]+curData;
if(tmp==target)
return tmp;
else if(tmp<target)
{
if(abs(tmp-target) < abs(closet-target))
closet=tmp;
while(l<r && nums[l]==nums[l+1]) l++;
l++;
}
else
{
if(abs(tmp-target) < abs(closet-target))
closet=tmp;
while(l<r && nums[r]==nums[r-1]) r--;
r--;
}
}
return closet;
}
int threeSumClosest(vector<int>& nums, int target) {
int closetTarget=nums[0]+nums[1]+nums[2];
int twoRet;
int len=nums.size();
sort(nums.begin(), nums.end());
for(int i=0; i<len-2; i++)//或许前面的题目这里不是重点,但在此处必须保证i后面有两个元素或以上,否则会出错
{
if(i>0 && nums[i]==nums[i-1])
continue;
twoRet=towSumCloset(nums, i+1, nums[i], target);
if(twoRet==target)
return target;
else
{
if(abs(target-closetTarget) > abs(target-twoRet))
closetTarget=twoRet;
}
}
return closetTarget;
}
};
3. 4sum问题
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)
解析:
4sum问题甚至到ksum都可以用改方法一步的完善,只是,写函数时,要将4,5,6,等用参数的形式传进去就可以了
class fourSum{
public:
int len;
vector<int> line;//这里自己定义了line,可以减少成员函数的参数个数
void TwoSum(vector<vector<int>> & ret, vector<int> & nums, int begin, int target){
int l=begin;
int r=len-1;
while(l<r){
if(nums[l]+nums[r]==target){
line[2]=nums[l];
line[3]=nums[r];
ret.push_back(line);
while(l<r && nums[l+1]==nums[l]) l++;
while(l<r && nums[r]==nums[r+1]) r--;
l++;
r--;
}
else if(nums[l]+nums[r]<target)
l++;
else
r--;
}
}
void ThreeSum(vector<vector<int>> & ret, vector<int> & nums, int begin, int target){
for(int i=begin; i<len-2; i++){
if(i>begin && nums[i]==nums[i-1])
continue;
line[1]=nums[i];
TwoSum(ret, nums, i+1, target-nums[i]);
}
}
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> ret;
if(nums.size()<4)
return ret;
line.resize(4);
len=nums.size();
sort(nums.begin(), nums.end());
for(int i=0; i<nums.size()-3; i++){
if(i>0 && nums[i]==nums[i-1])
continue;
else{
line[0]=nums[i];
ThreeSum(ret, nums, i+1, target-nums[i]);
}
}
return ret;
}
};
更经典的解法见:http://tech-wonderland.net/blog/summary-of-ksum-problems.html
03 | vector< vector > findZeroSumInSortedArr(vector &num, int begin, int count, int target) |
10 | int i = begin, j = num.size()-1; |
13 | int sum = num[i] + num[j]; |
14 | if (sum == target && visited.find(num[i]) == visited.end()) |
17 | visited.insert(num[i]); |
18 | visited.insert(num[j]); |
19 | tuple.push_back(num[i]); |
20 | tuple.push_back(num[j]); |
24 | else if (sum < target) |
36 | for ( int i=begin; i<num.size(); i++) |
38 | if (visited.find(num[i]) == visited.end()) |
40 | visited.insert(num[i]); |
41 | vector subRet = findZeroSumInSortedArr(num, i+1, count-1, target-num[i]); |
44 | for ( int j=0; j<subRet.size(); j++) |
46 | subRet[j].insert(subRet[j].begin(), num[i]); |
49 | ret.insert(ret.end(), subRet.begin(), subRet.end()); |
58 | vector threeSum(vector &num) { |
59 | sort(num.begin(), num.end()); |
60 | return findZeroSumInSortedArr(num, 0, 3, 0); |
63 | vector fourSum(vector &num, int target) { |
64 | sort(num.begin(), num.end()); |
65 | return findZeroSumInSortedArr(num, 0, 4, target); |