【LeetCode热题100】【双指针】三数之和
给你一个整数数组 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 。
提示:
3 <= nums.length <= 3000
-105 <= nums[i] <= 105
题解
前有两数之和用哈希在O(n)的时间复杂度内解决,现有三数之和需要用到双指针在O(n²)内解决
暴力的话需要三层循环而且需要去重复
我们可以先从小到大排序一下元素,那么现在元素是有序的了,而且左边的比右边的小或者相等
如果某元素大于0了,那么这个元素后面是不会有答案出现了,因为后面的元素不会比前面的小
找到一个小于等于0的元素了,让左指针指向后面一个元素,右指针指向最大的元素,把他们相加起来,如果和等于0,那么这三个是一个答案存起来,继续看左边的元素往右有没有相同的元素,如果有的话更新一下左边指针,因为这三个数字的组合已经是答案了,相同的就是重复了,然后同样看右边的元素往左有没有相同的元素,有的话也更新一下
如果和不等于0,和比0小,那么移动左指针让候选元素变大,如果和比0大,那么移动右指针让候选元素变小
排序nlogn,遍历元素n,两层while循环因为循环条件都是一起的加起来也是n,所以就是n²
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;
}
};