一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第26天,点击查看活动详情。
题目描述
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4] 输出:[[-1,-1,2],[-1,0,1]]
示例 2:
输入:nums = [] 输出:[]
示例 3:
输入:nums = [0] 输出:[]
提示:
- 0 <= nums.length <= 3000
- -105 <= nums[i] <= 105
思路
本题主要考察双指针算法。首先对数组进行排序,排序后选定第一个数 nums[i],再使用左右指针指向 nums[i]后面的两端,计算三个数的和 sum 判断是否满足为 0,满足则添加进结果集。如果 nums[i]大于 0,则三数之和必然无法等于 0,结束循环 。如果 nums[i] == nums[i-1],则说明该数字重复,会导致结果重复,所以应该跳过。
注意:
- 当 sum == 0 时,nums[L] == nums[L+1] 则会导致结果重复,应该跳过,L ++
- 当 sum == 0 时,nums[R] == nums[R-1] 则会导致结果重复,应该跳过,R --
代码
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
int length = nums.size();
// 当数组中的元素小于3时,不可能构成3元组
if(length < 3) return res;
// 对数组进行排序
sort(nums.begin(), nums.end());
// 从前到后,先确定第一个数子,再通过双指针去找以第一个数作为基数的,三元组的所有可能情况
for(int i = 0;i < length;i ++)
{
// 当第一个数大于0时,由于是排序数组,后面所有的数都大于0,不可能找到满足条件的三元组
if(nums[i] > 0) return res;
// 当第一个数和下一个数重复时,找到的情况相同,需要跳过
if(i > 0 && nums[i] == nums[i - 1]) continue;
// 定义左右指针
int left = i + 1, right = length - 1;
while(left < right)
{
// 当三数之和小于0时,移动左指针
if(nums[i] + nums[left] + nums[right] < 0)
{
left ++;
}
// 当三数之和大于0时,移动右指针
else if(nums[i] + nums[left] + nums[right] > 0)
{
right --;
}
else
{
vector<int> ans;
// 把满足条件的三元组加入答案数组中
ans.push_back(nums[i]), ans.push_back(nums[left]), ans.push_back(nums[right]);
res.push_back(ans);
// 对left去重
while(left < right && nums[left] == nums[left + 1]) left ++;
// 对right去重
while(left < right && nums[right] == nums[right - 1]) right --;
left ++, right --;
}
}
}
return res;
}
};