1. 题目解析
Leetcode链接:15. 三数之和
在寻找和为零的不重复三元组时,"不重复"指的是三元组中的每个元素在不同的位置上。为了更清晰地说明这一点,让我们以第一个示例为例:
在这个示例中,我们找到了三个满足条件的三元组。然而,在最后的返回结果中,只包含了两个三元组。这是因为在考虑三元组的唯一性时,元素的相对位置也被纳入考虑。换句话说,如果三元组的元素相同,但它们的位置不同,仍然被视为不同的三元组。
如果没有找到满足条件的三元组,那么返回一个空集。
2. 算法原理
首选的解决方案当然是采用暴力枚举方法。具体而言,我们可以先对数据进行排序,然后进行暴力枚举,最后利用集合(set)来去除重复项。
然而,我们需要思考如何优化N3的暴力枚举过程。由于排序后得到有序数组,我们应该考虑使用二分查找或双指针法进行优化。在这方面,双指针法显然是首选。
- 先排序;
- 然后固定⼀个数 a :
- 在这个数后⾯的区间内,使⽤「双指针算法」快速找到两个数之和等于 -a 即可。
但是要注意的是,这道题⾥⾯需要有「去重」操作~
- 找到⼀个结果之后, left 和 right 指针要「跳过重复」的元素
- 当使⽤完⼀次双指针算法之后,固定的 a 也要「跳过重复」的元素
3. 代码编写
class Solution
{
public:
vector<vector<int>> threeSum(vector<int>& nums)
{
vector<vector<int>> ret;
// 1. 排序
sort(nums.begin(), nums.end());
// 2. 利⽤双指针解决问题
int n = nums.size();
for(int i = 0; i < n; ) // 固定数 a
{
if(nums[i] > 0) break; // ⼩优化
int left = i + 1, right = n - 1, target = -nums[i];
while(left < right)
{
int sum = nums[left] + nums[right];
if(sum > target) right--;
else if(sum < target) left++;
else
{
ret.push_back({nums[i], nums[left], nums[right]});
left++, right--;
// 去重操作 left 和 right
while(left < right && nums[left] == nums[left - 1]) left++;
while(left < right && nums[right] == nums[right + 1]) right--;
}
}
// 去重 i
i++;
while(i < n && nums[i] == nums[i - 1]) i++;
}
return ret;
}
};
The Last
嗯,就是这样啦,文章到这里就结束啦,真心感谢你花时间来读。
觉得有点收获的话,不妨给我点个赞吧!
如果发现文章有啥漏洞或错误的地方,欢迎私信我或者在评论里提醒一声~