题目大意
给你一个数组nums,要求找到所有不重复的和为target的四元组。
题解
和三数之和的思路一致,排序后双指针,只不过四数之和相比三数之和需要多加一个for循环,同AC代码:
class Solution {
public:
typedef long long LL;
int min(int a,int b,int c,int d){
return ::min(a,::min(b,::min(c,d)));
}
int max(int a,int b,int c,int d){
return ::max(a,::max(b,::max(c,d)));
}
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> res;
const int sz = nums.size();
sort(nums.begin(),nums.end());
if(sz < 4)return res;
if(target <= 0 && nums[0] > 0)return res;
if(target >= 0 && nums[sz-1] < 0)return res;
if(target > 0 && nums[0] > 0 && nums[0] > target)return res;
if(target < 0 && nums[sz-1] < 0 && nums[sz-1] < target)return res;
int l,r;
for(int i = 0;i < sz; ++i){
if(i > 0 && nums[i] == nums[i-1])continue;
for(int j = i+1;j < sz; ++j){
if(j > 1 && j-1 != i && nums[j] == nums[j-1])continue;
l = j+1;
r = sz-1;
LL sum;
while(l < r){
// int nmin = min(nums[i],nums[j],nums[l],nums[r]);
// int nmax = max(nums[i],nums[j],nums[l],nums[r]);
// if((nmin > 0 && target >= 0 && nmin >= target)
// || (nmax < 0 && target <= 0 && nmin <= target)
// || (nmax < 0 && target >= 0)
// || (nmin > 0 && target <= 0)){
// ++l,--r;
// continue;
// }
sum = (LL)nums[i] + (LL)nums[j] + (LL)nums[l] + (LL)nums[r];
if(sum == (LL)target){
res.push_back({nums[i],nums[j],nums[l],nums[r]});
while(l < r && nums[l] == nums[l+1])++l;
while(l < r && nums[r] == nums[r-1])--r;
--r,++l;
}
else if(sum > (LL)target)--r;
else if(sum < (LL)target)++l;
}
}
}
return res;
}
};
剪枝思路
将数组排序后,对符合以下条件的样例剪枝:
- target为负数或0,且数组首元素(排序后首元素即是数组最小值)大于0
- target为正数或0,且数组末尾元素(即是数组最大值)小于0
- target为正数,数组首元素为正数,且数组首元素大于target
- target为负数,数组末尾元素为负数,且数组末尾元素小于target
上述情况均无解,可以直接返回空vector。
此外,还可以根据找出的四元组进行剪枝,即是代码中注释掉的地方,但是会引入额外的时间开销且没有必要性,所以可以不用考虑。