一、题目
给你一个包含 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
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum
二、解题
双指针法思路:
第一步:对数组进行排序,排序后固定一个数 nums[i],可以从0下标开始;
第二步:使用左右指针指向 nums[i]后面数组的两端,数字分别为 nums[left] 和 nums[right],
第三步:计算三个数的和 sum 判断是否满足为 0,满足则添加进结果集满足后的判决条件:
如果 nums[i] > 0,则三数之和必然无法等于 0,结束循环;
如果 nums[i] == nums[i−1],则说明该数字重复,会导致结果重复,所以应该跳过;
if sum == 0,nums[left] == nums[left+1]则会导致结果重复,应该跳过,left++;
if sum == 0,nums[right] == nums[right-1]则会导致结果重复,应该跳过,right--;不满足的判决条件:
if sum > 0,则需要左移right指针,找下一个相对小的数;
if sum < 0, 则需要右移left指针,找下一个相对大的数。
代码一:效率低,未满足时间约束
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int size = nums.size();
if (size < 3)
return {};
std::sort(nums.begin(), nums.end());
if (nums[size - 1] < 0)
return {};
vector<vector<int>> result;
for (int i = 0; i < size; ++i)
{
int left = i + 1;
int right = size - 1;
int currentVal = nums[i];
if (currentVal > 0)
return result;
if (i > 0 and nums[i - 1] == currentVal)
continue;
while (left < right)
{
int sum = currentVal + nums[left] + nums[right];
if (sum == 0)
{
vector<int> tmp{currentVal, nums[left], nums[right]};
auto it = std::find(result.begin(), result.end(), tmp);
if (it == result.end())
result.emplace_back(tmp);
while (left < right and nums[left] == nums[left + 1])
++left;
while (left < right and nums[right - 1] == nums[right])
--right;
++left;
--right;
}
else if (sum < 0)
{
++left;
}
else
{
--right;
}
}
}
return result;
}
};
代码二:利用set代替vector减少插入结果集时的查找,提升效率,解决时间约束问题
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int size = nums.size();
if (size < 3)
return {};
std::sort(nums.begin(), nums.end());
if (nums[size - 1] < 0)
return {};
set<vector<int>> result;
for (int i = 0; i < size; ++i)
{
int left = i + 1;
int right = size - 1;
int currentVal = nums[i];
if (currentVal > 0)
break;
if (i > 0 and nums[i - 1] == currentVal)
continue;
while (left < right)
{
int sum = currentVal + nums[left] + nums[right];
if (sum == 0)
{
result.insert({currentVal, nums[left], nums[right]});
while (left < right and nums[left] == nums[left + 1])
++left;
while (left < right and nums[right - 1] == nums[right])
--right;
++left;
--right;
}
else if (sum < 0)
{
++left;
}
else
{
--right;
}
}
}
return vector<vector<int>>(result.begin(), result.end());
}
};
【注】首要是保证结果正确后,再来对效率进行优化。