题目链接
一. 题目描述

cpp
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
}
};
二. 解题思路
1)本题解题思路和上一篇的三数之和基本一样,只不过多固定一个数,再用双指针。
2)如果使用暴力解法来暴力枚举四个数,时间复杂度将是O(N^4)级别的,双指针算法可以降一维达到O(N^3)。

3)优化算法核心思路
-
排序。
-
依次固定一个数a。
-
在a后面的区间使用 "三数之和" 找到三个数。
-
在三数之和的方法中:依次固定一个数b。
-
在后面的区间内,使用 "双指针算法" 找到两个数,使这两个数的和为 target - a - b。
-
细节问题
① 不漏:找到一组正确的值之后,不要停止,两指针继续向内移动缩小区间继续寻找。
② 不重:不重复这里有三个位置需要注意,第一个双指针位置不能指向重复值;第二个是固定的数b不能固定重复的值;第三个是固定的数a不能固定重复的值。
三. 易错测试用例
nums = { 1000000000,1000000000,1000000000,1000000000 };
target = -294967296;
这条测试用例中的值是10^9,和int的最大值是同一个量级的,在加减运算时会溢出。所以我们要用范围更大的long long。

四. 代码实现
cpp
class Solution
{
public:
vector<vector<int>> fourSum(vector<int>& nums, int target)
{
vector<vector<int>> retvv;
size_t size = nums.size();
sort(nums.begin(), nums.end());
// 依次固定第一个数
for(size_t i = 0; i < size; i++)
{
// 第一个固定的数不重复
if(i && nums[i] == nums[i-1]) continue;
// 依次固定第二个数
for(size_t j = i + 1; j < size; j++)
{
// 第二个固定的数不重复
if(j != i+1 && nums[j] == nums[j-1]) continue;
size_t left = j+1, right = size-1;
long long newtarget = (long long)target - nums[i] - nums[j];
// 找双指针指向元素之和等于newtarget
while(left < right)
{
long long sum = nums[left] + nums[right];
if(sum > newtarget) right--;
else if(sum < newtarget) left++;
else
{
retvv.push_back({nums[i], nums[j], nums[left], nums[right]});
// 不漏,找到一组之后不能停,继续向内缩小区间寻找
left++;right--;
// 双指针这层不能重复
while(left < right && nums[left] == nums[left-1]) left++;
while(left < right && nums[right] == nums[right+1]) right--;
}
}
}
}
return retvv;
}
};