给你一个整数数组 nums
,判断是否存在三元组 [nums[i], nums[j], nums[k]]
满足 i != j
、i != k
且 j != k
,同时还满足 nums[i] nums[j] nums[k] == 0
。请
你返回所有和为 0
且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
代码语言:javascript复制输入: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:
代码语言:javascript复制输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。
示例 3:
代码语言:javascript复制输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。
提示:
3 <= nums.length <= 3000
-105 <= nums[i] <= 105
题解
前有两数之和用哈希在O(n)的时间复杂度内解决,现有三数之和需要用到双指针在O(n²)内解决
暴力的话需要三层循环而且需要去重复
我们可以先从小到大排序一下元素,那么现在元素是有序的了,而且左边的比右边的小或者相等
如果某元素大于0了,那么这个元素后面是不会有答案出现了,因为后面的元素不会比前面的小
找到一个小于等于0的元素了,让左指针指向后面一个元素,右指针指向最大的元素,把他们相加起来,如果和等于0,那么这三个是一个答案存起来,继续看左边的元素往右有没有相同的元素,如果有的话更新一下左边指针,因为这三个数字的组合已经是答案了,相同的就是重复了,然后同样看右边的元素往左有没有相同的元素,有的话也更新一下
如果和不等于0,和比0小,那么移动左指针让候选元素变大,如果和比0大,那么移动右指针让候选元素变小
排序nlogn,遍历元素n,两层while循环因为循环条件都是一起的加起来也是n,所以就是n²
代码语言:javascript复制class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
if(nums.size()<3)
return {};
sort(nums.begin(),nums.end());
if(nums[0]>0) // 如果最小的都大于0了那么肯定没有
return {};
vector<vector<int>>answer;
for(int i=0;i<nums.size();i ){
if(i>0&&nums[i]==nums[i-1]) // 元素相同的不做判断
continue;
int left=i 1,right=nums.size()-1; // 取左右双指针
while(left<right){
int sum=nums[i] nums[left] nums[right];
if(sum==0){
answer.push_back({nums[i],nums[left],nums[right]});
while(left<right&&nums[left]==nums[left 1]){left ;} // 左边相同的去掉
while(left<right&&nums[right-1]==nums[right]){right--;} // 右边相同的去掉
left ;
right--;
}else if(sum<0){ // 和不为0但是小于0说明和太小了移动左指针变大
left ;
} else{ // 移动右指针变小
right--;
}
}
}
return answer;
}
};