给定一个包含 n 个整数的数组 nums
和一个目标值 target
,判断 nums
中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target
相等?找出所有满足条件且不重复的四元组。
注意:
答案中不可以包含重复的四元组。
示例:
给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。 满足要求的四元组集合为: [ [-1, 0, 0, 1], [-2, -1, 1, 2], [-2, 0, 0, 2] ]
分析:
如果是两数和问题,可以采用排序+双指针法,复杂度为o(nlogn)
而这个问题是四数和,所以要尽可能的转化为两数和问题,考虑在搜索的过程中如何剪枝。
首先肯定要固定前两个数,如果先对数组进行一次排序,就很容易得出如下剪枝方案:
设数组为nums,第一个数下标为i,第二数下标为j,数组的长度为len
nums[i]+nums[len-3]+nums[len-2]+nums[len-1] < target 直接i+1
nums[i]+nums[i+1]+nums[i+2]+nums[i+3] > target 直接退出循环
nums[i]+nums[j]+nums[len-2]+nums[len-1] < target 直接j+1
nums[i]+nums[j]+nums[j+1]+nums[j+2]>target 直接退出循环
固定前两个数后就转换为了两数和问题。
还有一个问题就是不能有重复的集合,因此在对四个数的进行遍历的时候,都需要考虑与相应的前一位数是否相同,如果相同就应该直接跳过,不然就会出现重复的问题。
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> result;
sort(nums.begin(),nums.end());
int length = nums.size();
for(int i = 0 ; i < length - 3 ; i ++ )
{
if(nums[i] + nums[i+1] + nums[i+2] + nums[i+3] > target) break;
if(i > 0 && nums[i] == nums[i-1]) continue;
if(nums[i] + nums[length-3] + nums[length-2] + nums[length - 1] < target) continue;
for(int j = i + 1 ; j < length - 2 ; j ++ )
{
if(nums[i]+nums[j]+nums[j+1]+nums[j+2] > target) break;
if(j > i + 1 && nums[j] == nums[j-1]) continue;
if(nums[i]+nums[j]+nums[length-2]+nums[length-1] < target) continue;
int t = target - nums[i] - nums[j];
int left = j + 1;
int right = length - 1;
while(left < right)
{
if(nums[left] + nums[right] > t) right--;
else if(nums[left] + nums[right] < t) left++;
else{
vector<int> res;
res.push_back(nums[i]);
res.push_back(nums[j]);
res.push_back(nums[left]);
res.push_back(nums[right]);
result.push_back(res);
do{left++;}while(nums[left]==nums[left-1]);
do{right--;}while(nums[right]==nums[right+1]);
}
}
}
}
return result;
}
};