18. 四数之和
题目来源:18. 四数之和
解题思路
本题使用双指针法进行解题,首先我们从起始位置为0和1的地方,嵌套遍历数组,分别代表a,b的下标。然后使用双指针一头一尾进行移动,头尾指针分别代表c,d的下标。如果当前a,b,c,d和比目标值target大,则移动尾指针,否则移动头指针。
难点分析
本题难点在于去重,题目给出的样例中有:nums = [2,2,2,2,2], target = 8,可以发现,元素本身是重复的,我们最终的答案只能是唯一的,即:[[2,2,2,2]],换言之,每一个元素只能被取一次。
再看这个例子:nums = [2,2,1,3,4],target = 10 这里的正确答案是:[[1,2,3,4]]而不是[[1,2,3,4],[1,2,3,4]],因为如果2被取两次,则结果集重复。
小结一下,对于本题可能存在三两种重复的情况:
- 元素本身重复
- a,b,c,d 之间重复取值
- 结果集重复
如何避免结果集重复呢?只需要避免前两条即可,所以重点在于如何避免重复对a,b,c,d取值和如何对跳过重复元素只选一次。
对于上述两个难点,我们可以先对nums进行排序,这样重复的元素就是相邻的,我们判断相邻是否相等即可,避免a,b,c,d之间是否重复也是同理。
具体代码实现中需要注意的点
- nums必须先排序后遍历
- 在取abcd的时候需要判断下标是否越界。
- 取值过程中的去重是当前下标向后比较,取结果集后的去重则相反。
代码实现
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
long sum = 0;
vector<vector<int>> result;
sort(nums.begin(), nums.end());
for(int i = 0;i < nums.size() ;i++)
{
if(i > 0 && nums[i] == nums[i - 1])
continue;
int a = nums[i];
for(int j = i + 1 ;j < nums.size();j++)
{
if(j > i + 1 && nums[j] == nums[j - 1])
continue;
int b = nums[j];
int left = j + 1;
int right = nums.size() - 1;
while(left < right)
{
if(left > j + 1 && nums[left] == nums[left - 1])
{
left++;
continue;
}
int c = nums[left];
if(right < nums.size() - 1 && nums[right] == nums[right + 1])
{
right--;
continue;
}
int d = nums[right];
sum = (long)a + b + c + d;
if(sum == target)
{
result.push_back({a,b,c,d});
while(left < right && nums[left] == nums[left + 1])
{
left++;
}
left++;
while(left < right && nums[right] == nums[right - 1])
{
right--;
}
right--;
}
else if(sum < target)
{
left++;
}
else
{
right--;
}
}
}
}
return result;
}
};

浙公网安备 33010602011771号