题目
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)
分析
类似于15题求解的3Sum问题,这次求解4Sum问题,本质是相同的,不可以采用穷举法;
其实求解4Sum问题可以分解为求3Sum问题,对数列依次遍历i,我们只需得到在第i个数后面,找出所有和为(target−nums[i])的三元组,同理求3Sum又可以退化为2Sum,进而退化为1Sum。
因此,采用递归的思想解决KSum问题 ,但是递归的性能总是不满意的 , 意料之中的TLE。
转换思路,我们可以使用2-sum的变形,两层遍历首先确定前两个元素,在确定后两个元素时采用2-sum的方式解决;
学习:关于2-sum 3-sum 和 4-sum 乃至于k-sum问题一个很好的总结。
AC代码
class Solution {
public:
/*4-sum算法,递归实现,TLE*/
vector<vector<int>> fourSum1(vector<int>& nums, int target) {
if (nums.empty())
return vector<vector<int>>();
sort(nums.begin(), nums.end());
return k_Sum(nums, 0, 4, target);
}
/*k-sum算法*/
vector<vector<int>> k_Sum(vector<int> &nums, int begPos, int count, int target)
{
if (nums.empty())
return vector<vector<int>>();
/*所输入序列为已排序*/
int len = nums.size();
unordered_set<int> visited;
vector<vector<int>> ret;
vector<int> tmp;
/*2-sum 处理*/
if (2 == count)
{
int i = begPos, j = len - 1;
while (i < j)
{
int sum = nums[i] + nums[j];
if (sum == target && visited.find(nums[i]) == visited.end())
{
tmp.clear();
tmp.push_back(nums[i]);
tmp.push_back(nums[j]);
ret.push_back(tmp);
/*加入已访问set*/
visited.insert(nums[i]);
visited.insert(nums[j]);
++i;
--j;
}//if
else if (sum < target)
++i;
else
--j;
}//while
}//if
else{
for (int i = begPos; i < len; ++i)
{
if (visited.find(nums[i]) == visited.end())
{
visited.insert(nums[i]);
/*得到k-1 sum的序列*/
vector<vector<int>> subRet = k_Sum(nums, i+1, count - 1, target-nums[i]);
if (!subRet.empty())
{
int sz = subRet.size();
for (int j = 0; j < sz; ++j)
{
subRet[j].insert(subRet[j].begin(), nums[i]);
}//for
ret.insert(ret.end(), subRet.begin(), subRet.end());
}//if
}//if
}//for
}//else
/*返回结果集*/
return ret;
}
/*4-sum算法,方法二,2-sum的变形*/
vector<vector<int>> fourSum(vector<int>& nums, int target) {
if (nums.empty() || nums.size() < 4)
return vector<vector<int>>();
sort(nums.begin(), nums.end());
int len = nums.size();
set<vector<int>> tmpRet;
vector<vector<int>> res;
for (int i = 0; i < len; ++i)
{
for (int j = i + 1; j < len; ++j)
{
int beg = j + 1, end = len - 1;
while (beg < end)
{
int sum = nums[i] + nums[j] + nums[beg] + nums[end];
if (sum == target)
{
vector<int> tmp = { nums[i], nums[j], nums[beg], nums[end] };
tmpRet.insert(tmp);
++beg;
--end;
}
else if (sum < target)
{
++beg;
}
else
--end;
}//while
}//for
}//for
auto iter = tmpRet.begin();
while (iter != tmpRet.end())
{
res.push_back(*iter);
++iter;
}//while
return res;
}
};