目录
1.题目描述:
给你一个由 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]]
2.算法解释:
-
排序数组:
- 首先对数组进行排序。排序的目的是为了方便后续的去重和双指针操作。
-
外层循环(固定第一个数):
- 使用一个外层循环遍历数组,固定第一个数
nums[first]
。 - 跳过重复的
nums[first]
以避免重复的四元组。
- 使用一个外层循环遍历数组,固定第一个数
-
内层循环(固定第二个数):
- 在第一个数的右侧,使用一个内层循环固定第二个数
nums[second]
。 - 跳过重复的
nums[second]
以避免重复的四元组。
- 在第一个数的右侧,使用一个内层循环固定第二个数
-
双指针法(寻找第三和第四个数):
- 在第二个数的右侧,使用双指针法(
left
和right
)来寻找剩下的两个数。 - 计算当前四个数的和
sum = nums[first] + nums[second] + nums[left] + nums[right]
。- 如果
sum == target
,将四元组加入结果集,并跳过重复的nums[left]
和nums[right]
。 - 如果
sum > target
,移动右指针right
向左以减少和。 - 如果
sum < target
,移动左指针left
向右以增加和。
- 如果
- 在第二个数的右侧,使用双指针法(
-
去重:
- 在每一步固定和移动指针时,都需要跳过重复的值,以确保结果中没有重复的四元组。
时间复杂度:
- 排序的时间复杂度为 O(n log n)。
- 外层循环为 O(n),内层循环为 O(n),双指针为 O(n),因此总的时间复杂度为 O(n^3)。
3.代码展示:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>>result;
//进行判断nums的个数
if (nums.size() < 4) {
return result;
}
//首先进行排序,以便后面的操作
sort(nums.begin(), nums.end());
for (int first = 0; first < nums.size() - 3; first++) {
//判断first是否重复,重复就跳过
if (first > 0 && nums[first] == nums[first - 1]) {
continue;
}
for (int second = first + 1; second < nums.size() - 2; second++) {
//判断second是否重复,重复就跳过
if (second > first + 1 && nums[second] == nums[second - 1]) {
continue;
}
//接下来利用双指针进行求解
int l = second + 1;//指向第三个元素
int r = nums.size() - 1;//指向最后一个元素
while (l < r)
{
int sums = nums[first] + nums[second] + nums[l] + nums[r];
if (sums == target) {
result.push_back({ nums[first] ,nums[second] ,nums[l] ,nums[r] });
//进行去重
while (l < r && nums[l] == nums[l+1])
{
l++;
}
l++;
while (l < r && nums[r] == nums[r - 1])
{
r--;
}
r--;
}
else if (sums > target) {
r--;
}
else
{
l++;
}
}
}
}
return result;
}