给定一个包含 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]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/4sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路1:想到的第一个方法是回溯,刚开始没有剪枝,超时。
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> ans;
vector<int> temp;
sort(nums.begin(),nums.end());
dfs(nums,0,target,ans,temp);
return ans;
}
void dfs(vector<int> &nums,int step,int target,vector<vector<int>> &ans,vector<int> &temp){
//if(step>nums.size()||temp.size()>4)
// return;
if(temp.size()==4){
if(target==0)
ans.push_back(temp);
return;
}
for(int i=step;i<nums.size();i++){
if(i>step&&nums[i]==nums[i-1])
continue; //去重
if(nums.size()-i<4-temp.size())
return; //剪枝
if(i<nums.size()-1&&(target-nums[i]-(int)(3-temp.size())*nums[i+1]<0))
return ; //剪枝,相当于sum和太大,后面的都剪掉
if(i<nums.size()-1&&target-nums[i]-(int)(3-temp.size())*nums[nums.size()-1]>0)
continue ; //注意这里是continue,因为相当于sum和太小
temp.push_back(nums[i]);
dfs(nums,i+1,target-nums[i],ans,temp);
temp.pop_back();
}
}
思路2: 和上面的有点类似,但使用了双指针,时间性能上有所优化。
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> ans;
int a,b,c,d,sum=0; //a,b,c,d代表下标
if(nums.size()<4)
return ans;
sort(nums.begin(),nums.end());
for(a=0;a<=nums.size()-4;a++){
if(a>0&&nums[a]==nums[a-1])
continue; //去重
for(b=a+1;b<=nums.size()-3;b++){
if(b>a+1&&nums[b]==nums[b-1])
continue; //记得是b>a+1,去重
if(nums[a]+nums[b]+2*nums[nums.size()-1]<target)
continue; //剪枝
if(nums[a]+nums[b]+2*nums[b+1]>target)
break; //剪枝
c=b+1;
d=nums.size()-1; //双指针法
while(c<d){
sum=nums[a]+nums[b]+nums[c]+nums[d];
if(sum<target)
c++;
else if(sum>target){
d--;
}
else{
ans.push_back({nums[a],nums[b],nums[c],nums[d]});
c++;
d--;
while(c<d&&nums[c]==nums[c-1]){
c++; //去重
}
while(c<d&&nums[d]==nums[d+1]){
d--; //去重
}
}
}
}
}
return ans;
}