给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
【题解】
本题实际上为两个元素为定值的一个升级版。同时求两个元素为定值又分已排序的数组和未排序的数组。
已排序数组:
一次循环,不用借助map。假设为从小到大排序数组,头元素索引begin,尾元素索引end。不断比较begin+end 和target的值,begin+end<target,让begin++, begin+end>target,让end--。同时注意去重即可。例如nums[begin] == nums[begin--]或nums[end]==nums[end+1]就continue
未排序数组:
1、暴力查找,2个for
2、借助map表,循环1次查找满足a+b=target的数组。
对于本题,因为为3个数相加a+b+c=0的情况,
暴力法为o(n^3),显然恐怖。所以可以直接排序,时间负责度o(n*logn),
再对排序后的数组,实行上述对于已排序数组寻找 a+b=target的解法即可。
//(nums[begin] == nums[begin-1] && begin>i+1)
//这一段是再提交过程中发现这类特例会出错。例如nums=[0,0,0,0] 会输出2组[0,0,0]
所以需要比较nums[begin] 和nums[begin-1],当begin++后。如果发现nums[begin] 和nums[begin-1]相等,即跳过。而begin>i+1是为了防止越界,因为需要比较的数中有一个为nums[begin-1]
//类似两个数求和=target,3个数求和为0,相当于target是变化的。
//先排序,这样可以去掉重复的target。毕竟排序时间复杂度也就o(n*logn)
//同时排序后,对于有序数组找target的。2333。前后同是便利即可。
vector<vector<int>> threeSum(vector<int>& nums) {
if(nums.size() < 3)
return {};
vector<vector<int>> res;
int n = nums.size();
sort(nums.begin(),nums.end());//先排序
for(int i = 0; i < n; i++) {
if(nums[i] > 0) // 排序后,大于0可以提前结束
break;
if(i > 0 && nums[i] == nums[i-1]) // 同样的target,过滤
continue;
int target = 0 - nums[i];
int begin = i + 1;
int end = n - 1;
while(begin<end) {
if((nums[begin] == nums[begin-1] && begin>i+1) || nums[begin] + nums[end] < target)
++begin;
else if(nums[begin] + nums[end] > target)
--end;
else {
res.push_back({nums[i],nums[begin],nums[end]});
begin++;
}
}
}
return res;
}