给你一个由 n
个整数组成的数组 nums
,和一个目标值 target
。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]]
(若两个四元组元素一一对应,则认为两个四元组重复):
0 <= a, b, c, d < n
a
、b
、c
和 d
互不相同nums[a] + nums[b] + nums[c] + nums[d] == target
你可以按 任意顺序 返回答案 。
示例 1:
输入:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
示例 2:
输入:nums = [2,2,2,2,2], target = 8
输出:[[2,2,2,2]]
提示:
1 <= nums.length <= 200
-109 <= nums[i] <= 109
-109 <= target <= 109
nums
进行排序,这样可以使得相同的数字相邻并方便后续的操作。nums[i]
,第二层循环从 i+1
到数组末尾选择第二个数字 nums[j]
。left
和 right
来寻找剩下的两个数字,使得四个数字的和等于目标值 target
。nums[i]
和 nums[j]
后,我们将问题转化为在剩下的数组部分中寻找两个数字,使得它们的和等于 target - nums[i] - nums[j]
。为了方便操作,我们将 target - nums[i] - nums[j]
记为 newTarget
。left
和 right
在剩下的数组部分中进行搜索。当 left
小于 right
时,我们计算当前的和 sum
,如果 sum
等于 newTarget
,则找到了一个满足条件的四元组,将其加入结果集。然后我们继续移动指针,并跳过重复的数字,直到找到下一个不同的数字。sum
小于 newTarget
时,我们将 left
指针右移一位,以增大和的值。当 sum
大于 newTarget
时,我们将 right
指针左移一位,以减小和的值。基于上述算法思路,下面是具体的实现代码:
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
sort(nums.begin(), nums.end()); // 对数组进行排序
vector<vector<int>> result; // 存储结果的数组
int n = nums.size();
for (int i = 0; i < n - 3; i++) {
// 外层剪枝操作
if (nums[i] > target && nums[i] > 0) {
break;
}
// 外层去重操作
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
for (int j = i + 1; j < n - 2; j++) {
// 内层剪枝操作
if (nums[i] + nums[j] > target && nums[j] > 0) {
break;
}
// 内层去重操作
if (j > i + 1 && nums[j] == nums[j - 1]) {
continue;
}
int left = j + 1;
int right = n - 1;
while (left < right) {
long sum = (long)nums[i] + (long)nums[j] + (long)nums[left] + (long)nums[right];
if (sum == target) {
result.push_back({nums[i], nums[j], nums[left], nums[right]});
// 内层去重操作
while (left < right && nums[left] == nums[left + 1]) {
left++;
}
while (left < right && nums[right] == nums[right - 1]) {
right--;
}
left++;
right--;
} else if (sum < target) {
left++;
} else {
right--;
}
}
}
}
return result;
}
};
现在我们对上述算法进行一些分析:
在上面的解法中,我们使用了双指针法和排序来解决这个问题。下面我们将介绍一下双指针法和排序的相关知识,并提供一个简单的示例代码。
双指针法是一种常用的算法技巧,它通过使用两个指针在数组中移动,从而解决一些问题。在本题中,我们使用了双指针法来寻找满足条件的四元组。通过固定前两个数字,然后使用双指针在剩下的数组部分中查找剩下的两个数字,使得它们的和等于目标值。通过左右指针的移动,我们可以有效地遍历所有可能的组合,并且通过剪枝操作和去重操作来提高效率。
排序在本题中起到了关键的作用。通过对输入数组进行排序,我们可以使得相同的数字相邻,方便后续的操作。排序后,我们可以通过双指针法在有序数组中查找满足条件的四元组。另外,排序还可以帮助我们进行剪枝操作和去重操作,从而减少计算量。
下面是一个简单的示例代码,展示了如何使用双指针法在有序数组中查找两个数的和等于目标值的情况:
#include
#include
using namespace std;
vector<vector<int>> twoSum(vector<int>& nums, int target) {
vector<vector<int>> result;
int left = 0;
int right = nums.size() - 1;
while (left < right) {
int sum = nums[left] + nums[right];
if (sum == target) {
result.push_back({nums[left], nums[right]});
left++;
right--;
} else if (sum < target) {
left++;
} else {
right--;
}
}
return result;
}
int main() {
vector<int> nums = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int target = 10;
vector<vector<int>> result = twoSum(nums, target);
for (const auto& res : result) {
for (int num : res) {
cout << num << " ";
}
cout << endl;
}
return 0;
}
在上面的示例代码中,我们定义了一个函数 twoSum,它接收一个有序数组 nums 和目标值 target,并返回满足条件的两个数的组合。通过设置左右指针,在遍历过程中不断调整指针的位置,我们可以找到满足条件的组合,并将其添加到结果中。