题目

知识点
剪枝处理
负数处理
举例说明
假设:数组中有负数,比如 [-5, -4, -2, 1, 3],target = -10
当前 nums[k] = -5,情况分析:-5 > -10 成立(因为 -5 确实大于 -10),
但如果没有 nums[k] >= 0 的限制,我们会直接 break,跳过了后续可能的解
实际上,-5 可以和 -4、-2、1 组合成 -10(-5 + -4 + -2 + 1 = -10)!
为什么需要 >= 0?
负数相加会变得更小:当数组中有负数时,即使当前数已经大于 target,加上后面的负数后,总和可能会变小,仍然可能等于 target。
非负数才具有单调性:只有当数组元素都大于等于 0 时,随着索引增加,和才会单调递增。这样一旦当前数大于 target,后面更大的数相加只会更大,肯定无法等于 target。
去重
思路
和 15 三数之和 都是一样的思路,利用排序+双指针 ,但是要再多加一层for循环
题解
cpp
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
sort(nums.begin(),nums.end());
vector<vector<int>> result;
for(int k=0;k<nums.size();k++){
//一级剪枝处理
if(nums[k]>=0 && nums[k]>target){
break;
}
//一级去重
if(k>0 && nums[k]==nums[k-1]){
continue;
}
for(int i=k+1;i<nums.size();i++){
//二级剪枝处理
if(nums[k]+nums[i]>=0 && nums[k]+nums[i]>target){
break;
}
//二级去重
if(i>k+1 && nums[i]==nums[i-1]){
continue;
}
int left=i+1;
int right=nums.size()-1;
while(left < right){
if((long)nums[k]+nums[i]+nums[left]+nums[right]>target) right--;
else if((long)nums[k]+nums[i]+nums[left]+nums[right]<target) left++;
else{
result.push_back(vector<int>{nums[k],nums[i],nums[left],nums[right]});
while(left<right&&nums[left]==nums[left+1]) left++;
while(left<right&&nums[right]==nums[right-1]) right--;
left++;
right--;
}
}
}//for i
}//for k
return result;
}
};