欢迎来到 CILMY23的博客
🏆本篇主题为:双指针算法之18. 四数之和(力扣)
🏆个人主页:CILMY23-CSDN博客
🏆系列专栏:Python | C++ | C语言 | 数据结构与算法 | 贪心算法 | Linux | 算法专题 | 代码训练营
🏆感谢观看,支持的可以给个一键三连,点赞收藏+评论。如果你觉得有帮助,还可以点点关注
题目:
给你一个由 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.给了一个目标值target
2.不重复的四元组
[nums[a], nums[b], nums[c], nums[d]]
3.找出不重复的四元组
0 <= a, b, c, d < n
a
、b
、c
和d
互不相同nums[a] + nums[b] + nums[c] + nums[d] == target
算法原理:
个人感觉:感觉四数之和比三数之和难多了
首先根据前两题的经验,我们很快就能推算出,这是一题双指针算法的题目,大致思路还是跟之前一样,双指针求和,然后去重。
所以我们能写出如下代码:
class Solution
{
public:
static vector<vector<int>> fourSum(vector<int>& nums, int target)
{
vector<vector<int>> ret;
//排序数组
sort(nums.begin(), nums.end());
int k = nums.size() - 1; //固定k
for (k = nums.size() - 1; k > 2;)
{
for (int j = k - 1; j > 1;)
{
int sum1 = nums[k] + nums[j];
int left = 0;
int right = j - 1;
while (left < right)
{
int sum2 = nums[left] + nums[right];
if (sum2 + sum1 == target)
{
ret.push_back({ nums[left],nums[right],nums[j],nums[k] });
left++;
right--;
}
else if (sum2 > (target - sum1))
{
right--;
}
else if (sum2 < (target - sum1))
{
left++;
}
}
}
}
return ret;
}
};
第一个,我用一个sum1进行存储两个固定的数的值,sum2存储两个指针的值。
接下来是重点,我的两个指针和两个固定的值相加要和target一样,所以两个指针的值要和target-sum1进行比较。
这个很重要,我当时和sum1比较发现是行不通的,没把target搞进去,因为我们最终是要和target目标值进行比较的。
接下来是去重,首先,是两个指针的去重,这个相对容易一些。
while (left < right && nums[left - 1] == nums[left])
{
left++;
}
while (left < right && nums[right + 1] == nums[right])
{
right--;
}
其次是两个固定数的去重,由于我这次去重将放在循环的末尾了,所以会有一些变化。
for (k = nums.size() - 1; k > 2;)
{
for (int j = k - 1; j > 1;)
{
//......
while (left < right)
{
//......
}
j--;
//j去重
while (j > 1 && nums[j + 1] == nums[j])
{
j--;
}
}
k--;
//k去重
while (k > 2 && nums[k + 1] == nums[k])
{
k--;
}
}
去重前,先保证固定的数会走到下一个位置,然后再进行比较。
然后还有一个坑的点是这题
会出现一个数值过大的问题,所以要把sum1和sum2都改成long long即可。
代码编写:
class Solution
{
public:
static vector<vector<int>> fourSum(vector<int>& nums, int target)
{
vector<vector<int>> ret;
//排序数组
sort(nums.begin(), nums.end());
int k = nums.size() - 1; //固定k
for (k = nums.size() - 1; k > 2;)
{
for (int j = k - 1; j > 1;)
{
long long int sum1 = nums[k] + nums[j];
int left = 0;
int right = j - 1;
while (left < right)
{
long long int sum2 = nums[left] + nums[right];
if (sum2 + sum1 == target )
{
ret.push_back({ nums[left],nums[right],nums[j],nums[k] });
left++;
right--;
while (left < right && nums[left - 1] == nums[left])
{
left++;
}
while (left < right && nums[right + 1] == nums[right])
{
right--;
}
}
else if (sum2 > (target-sum1))
{
right--;
}
else if (sum2 < (target-sum1))
{
left++;
}
}
j--;
//j去重
while (j > 1 && nums[j + 1] == nums[j])
{
j--;
}
}
k--;
//k去重
while (k > 2 && nums[k + 1] == nums[k])
{
k--;
}
}
return ret;
}
};
🛎️感谢各位同伴的支持,本期C++算法专题就讲解到这啦,下期我们将详解滑动窗口知识点,如果你觉得写的不错的话,可以给个一键三连,点赞,收藏+评论,可以的话还希望点点关注,若有不足,欢迎各位在评论区讨论。