18. 4Sum**

​https://leetcode.com/problems/4sum/description/​

题目描述

Given an array ​​nums​​​ of ​​n​​​ integers and an integer ​​target​​​, are there elements ​​a, b, c​​​ and ​​d​​​ in ​​nums​​​ such that ​​a + b + c + d = target​​​? Find all unique quadruplets in the array which gives the sum of ​​target​​.

Note:

The solution set must not contain duplicate quadruplets.

For example, given array ​​S = [1, 0, -1, 0, -2, 2]​​​, and ​​target = 0​​.

A solution set is:
[
[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]
]

给定一个整数数组和给定的 ​​target​​​, 是否存在 ​​a, b, c, d​​​ 4个整数使得它们的和满足 ​​a+b+c+d = target​​​? 返回所有不重复的 ​​(a, b, c, d)​​ 四元组.

解题思路

首先固定 a, 然后再使用 ​​3Sum​​ 的方法求解.

C++ 实现 1

class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
if (nums.size() < 4)
return {};

std::sort(nums.begin(), nums.end());
vector<vector<int>> res;
vector<int> path;
for (int i = 0; i < nums.size() - 3; ++i) {
for (int j = i + 1; j < nums.size() - 2; ++j) {
int lo = j + 1, hi = nums.size() - 1;
while (lo < hi) {
int sum = nums[i] + nums[j] + nums[lo] + nums[hi];
if (sum == target) {
path = {nums[i], nums[j], nums[lo], nums[hi]};
res.push_back(path);
while (lo < hi && nums[lo] == nums[lo + 1]) lo ++;
while (lo < hi && nums[hi] == nums[hi - 1]) hi --;
lo ++;
hi --;
}
else if (sum < target)
lo ++;
else
hi --;
}
while (j + 1 < nums.size() - 2 && nums[j + 1] == nums[j]) ++j;
}
while (i + 1 < nums.size() - 3 && nums[i + 1] == nums[i]) ++i;
}
return res;
}
};

C++ 实现 2

注意不要忘记先给数组排序, 此外还需要过滤重复元素.

class Solution {
private:
vector<vector<int>> threeSum(vector<int> &nums, int i, int j, int target) {
if (nums.size() < 3 || j - i < 2) return {};
vector<vector<int>> res;
for (int k = i; k < j - 1; ++ k) {
if (k == i || (k > i && nums[k] != nums[k - 1])) {
int lo = k + 1, hi = j;
while (lo < hi) {
int sum = nums[lo] + nums[hi] + nums[k];
if (sum == target) {
res.push_back({nums[k], nums[lo], nums[hi]});
while (lo + 1 < hi && nums[lo + 1] == nums[lo]) ++ lo;
while (hi - 1 > lo && nums[hi - 1] == nums[hi]) -- hi;
++ lo;
-- hi;
} else if (sum < target) ++ lo;
else -- hi;
}
}
}
return res;
}
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
if (nums.size() < 4) return {};
std::sort(nums.begin(), nums.end());
vector<vector<int>> res;
for (int i = 0; i < nums.size() - 3; ++ i) {
if (i == 0 || (i > 0 && nums[i] != nums[i - 1])) {
int aim = target - nums[i];
auto pairs = threeSum(nums, i + 1, nums.size() - 1, aim);
if (!pairs.empty())
for (auto &pair : pairs)
res.push_back({nums[i], pair[0], pair[1], pair[2]});
}
}
return res;
}
};

C++ 实现 3

过滤重复元素的方法和上一节不同.

class Solution {
private:
vector<vector<int>> twoSum(vector<int> &nums, int start, int target) {
vector<vector<int>> res;
int i = start, j = nums.size() - 1;
while (i < j) {
if (nums[i] + nums[j] == target) {
res.push_back({nums[i], nums[j]});
while (i < j && nums[i + 1] == nums[i]) i ++;
while (i < j && nums[j - 1] == nums[j]) j --;
i ++;
j --;
}
else if (nums[i] + nums[j] < target)
++ i;
else
-- j;
}
return res;
}
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
if (nums.size() < 4)
return {};

vector<vector<int>> res;
std::sort(nums.begin(), nums.end());
for (int i = 0; i < nums.size() - 3; ++i) {
for (int j = i + 1; j < nums.size() - 2; ++j) {
auto temp = twoSum(nums, j + 1, target - nums[i] - nums[j]);
if (!temp.empty())
for (auto &v : temp)
res.push_back({nums[i], nums[j], v[0], v[1]});

while (j + 1 < nums.size() - 2 && nums[j + 1] == nums[j]) ++j;
}
while (i + 1 < nums.size() - 3 && nums[i + 1] == nums[i]) ++i;
}
return res;
}
};