题目详情
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
——题目难度:中等
这道题的暴力解法比较好想,就是使用三重循环枚举所有可能的三元组,但假设最坏的情况下,数组中元素全是0则太费时间(因为很多组都是重复的,最后如果要解题还得去重)。
这里借用一下力扣题解里的,我觉得总结的非常好:
「不重复」的本质是什么?我们保持三重循环的大框架不变,只需要保证:
- 第二重循环枚举到的元素不小于当前第一重循环枚举到的元素;
- 第三重循环枚举到的元素不小于当前第二重循环枚举到的元素。
其实也就是:假设有这样一个三元组(a,b,c),其中a≤b≤c,当暴力三重循环解出来的会有(b,a,c)、(c,b,a)、(a,c,b)等等。
所以我们优化的时候可以使得ans里不存在重复的三元组,要做到只需将原数组排好序,这样再三重循环的话就不会出现除了(a,b,c)的情况,因为a≤b≤c这是必须满足的。
然后可以发现第二层和第三层的for循环(也就是枚举second和third的) 其实是可以改进的。a+b+c=0,当a不变,b往后遍历也就是不断变大,发现要满足a+b+c=0的话,其实c是不断在减小的,所以我们可以从小到大枚举b,同时从大到小枚举c。当发现a+b+c<0的时候,可以令b变大以满足等式;当发现a+b+c>0的时候,可以令c变小以满足等式。
同时要注意 b<=c,也要注意第一层for循环枚举a的时候,需要保证a每次都不一样,b和c类似a的情况。
-解题代码
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> ans;
int n = nums.size();
if (n < 3) return ans;
sort(nums.begin(), nums.end());
for(int first = 0; first < n-2; first++)
{
if(first > 0 && nums[first] == nums[first-1])
continue;
int target = -nums[first];
int second = first + 1;
int third = n - 1;
while (second < third) {
int sum = nums[second] + nums[third];
if (sum == target) {
ans.push_back({nums[first], nums[second], nums[third]});
while(second < third && nums[second] == nums[second+1]) {
second++;
}
second++;
while(second < third && nums[third] == nums[third-1]) {
third--;
}
third--;
} else if (sum > target) {
third--;
} else {
second++;
}
}
}
return ans;
}
};