对撞双指针(七)三数之和
15. 三数之和
给你一个整数数组
nums
,判断是否存在三元组[nums[i], nums[j], nums[k]]
满足i != j
、i != k
且j != k
,同时还满足nums[i] + nums[j] + nums[k] == 0
。请你返回所有和为0
且不重复的三元组。注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4] 输出:[[-1,-1,2],[-1,0,1]] 解释: nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。 nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。 nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。 不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。 注意,输出的顺序和三元组的顺序并不重要。示例 2:
输入:nums = [0,1,1] 输出:[] 解释:唯一可能的三元组和不为 0 。示例 3:
输入:nums = [0,0,0] 输出:[[0,0,0]] 解释:唯一可能的三元组和为 0 。
首先利用双指针思想进行寻找合适的三个数,再利用set进行去重。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int n = nums.size();
set<vector<int>> res;
sort(nums.begin(), nums.end());
for(int i = n-1; i > 1; i--)
{
int c = nums[i];
int temp = 0-c;
int left = 0, right = i-1;
while(left < right)
{
if(nums[left] + nums[right] < temp)
left++;
else if(nums[left] + nums[right] > temp)
right--;
else
{
res.insert({nums[left], nums[right], c});
left++;
}
}
}
vector<vector<int>> ret;
for(auto it : res)
{
ret.push_back(it);
}
return ret;
}
};
离谱……………………
对于去重的方法有进一步优化
将c从右向左固定:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int n = nums.size();
vector<vector<int>> ret;
sort(nums.begin(), nums.end()); 1、排序
for(int i = n-1; i > 1; )
{
int c = nums[i];
int temp = 0-c;
int left = 0, right = i-1;
while(left < right) 2、此处使用双指针思想
{
if(nums[left] + nums[right] < temp)
left++;
else if(nums[left] + nums[right] > temp)
right--;
else
{
ret.push_back({nums[left], nums[right], c});
int flag = nums[left++];
while(left<right && nums[left] == flag)
left++; 3、对于去重操作的优化①
flag = nums[right--];
while(left<right && nums[right] == flag)
right--;
}
}
i--; 4、去重的优化②
while(i>1 && nums[i+1] == nums[i]) // 把whlie写错成if调试半天才发现
i--;
}
return ret;
}
};
将c从左向右固定
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int n = nums.size();
sort(nums.begin(), nums.end()); // 1、排序
vector<vector<int>> ret;
for(int i = 0; i < n; )
{
if(nums[i] > 0) break; // 2、作一个小优化,如果左边数大于零则无法满足和为0
int left = i+1, right = n-1;
int target = -nums[i];
while(left < right) // 3、双指针进行寻找
{
int sum = nums[left] + nums[right];
if(sum < target) left++;
else if(sum > target) right--;
else
{
ret.push_back({nums[i], nums[left++], nums[right--]});
while(left < right && nums[left] == nums[left-1])
left++; // 当left位置重复时,left后移
while(left < right && nums[right] == nums[right+1])
right--; // 当right位置重复时,right左移
}
}
i++;
while(i < n && nums[i]==nums[i-1])
i++;
}
return ret;
}
};