题目大意
给你一个数组nums,要求找到所有不重复的和为target的四元组。
18. 四数之和
题解
和三数之和的思路一致,排序后双指针,只不过四数之和相比三数之和需要多加一个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。
此外,还可以根据找出的四元组进行剪枝,即是代码中注释掉的地方,但是会引入额外的时间开销且没有必要性,所以可以不用考虑。