给定一个包含 n 个整数的数组 nums
,判断 nums
中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4], 满足要求的三元组集合为: [ [-1, 0, 1], [-1, -1, 2] ]
思考:
题目中要找“a + b + c = 0 ”的三个数,除了三个数字全部是0之外,肯定是有正数有负数的;所以可以使用一个for循环去固定一个数,然后去考虑剩下两个数字,只要找到两个数且和为第一个固定数的相反数就行了,那么如果能更有效的定位呢?
如果数组是无序的,只能通过遍历得到所有的组合;
但是如果数组是有序的,就可以用双指针以线性时间复杂度来遍历所有满足题意的两个数组合。
首先对数组进行排序,然后进行判断,如果数组为空||数组第一个数字都是正数||数组最后一个数字都是负数就可以直接返回了。
(顺序一定不能错了,因为如果先不判断是否为空,就去调用front(),会显示造成迭代器错误;并且判断条件是:非0为真,一开始用front()直接判断就错了)
if (nums.empty() || nums.front()>0 || nums.back()<0)
return{};
然后开始遍历排序后的数组。这里做个剪枝优化,就是当遍历到正数的时候就break。因为后面和肯定大于0了。
之后还有一个重复跳过的过程;以及这里并不是和twosum找到了就break,因为题目中可能有几种解,还要继续遍历下去。
如果两数之和小于target,则我们将左边那个指针left右移一位;如果两数之和大于target,则我们将右边那个指针right左移一位
以及用set去去除vector<vector<int>>中可能产生的重复项。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
set<vector<int>> res;
sort(nums.begin(), nums.end());
if (nums.empty() || nums.front()>0 || nums.back()<0)
return{};
for (int i = 0; i<nums.size(); i++) {
if (nums[i] > 0)
break;
int target = 0 - nums[i];
int left = i + 1, right = nums.size() - 1;
while (left < right) {
if (nums[left] + nums[right] == target) {
res.insert({ nums[i],nums[left],nums[right] });
while (left < right &&nums[left] == nums[left + 1])
left++;
while (left < right &&nums[right] == nums[right - 1])
right--;
left++;
right--;
}
else if (nums[left] + nums[right] > target) {
right--;
}
else {
left++;
}
}
}
return vector<vector<int>>(res.begin(), res.end());
}
};
感觉还是下面这种好,直接判断固定的数字是不是重复出现的。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
sort(nums.begin(), nums.end());
if (nums.empty() || nums.front()>0 || nums.back()<0)
return res;
for (int i = 0; i<nums.size(); i++) {
if (nums[i] > 0)
break;
if(i > 0 && nums[i] == nums[i-1]) //判断下固定的数字是不是重复出现
continue;
int target = 0 - nums[i];
int left = i + 1, right = nums.size() - 1;
while (left < right) {
if (nums[left] + nums[right] == target) {
res.push_back({ nums[i],nums[left],nums[right] });
while (left < right &&nums[left] == nums[left + 1])
left++;
while (left < right &&nums[right] == nums[right - 1])
right--;
left++;
right--;
}
else if (nums[left] + nums[right] > target) {
right--;
}
else {
left++;
}
}
}
return res;
}
};