Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note: The solution set must not contain duplicate triplets.
For example, given array S = [-1, 0, 1, 2, -1, -4],
A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
]
思路:
1. 简单粗暴的做法就是三重循环,找到答案。如何降低复杂度?2sum时,用hash降低了复杂度。而且我们也知道,除了hash,还可以用two pointer也可以降低复杂度。用hash不好去重复!
2. 先排序,然后用two pointer,普通的遍历,总是从左往右,two pointer则是一个在左边,一个在右边,根据不同的条件,判断是移动左边还是移动右边或者同时移动,最后左右两个指针在中间相遇,这也是一种遍历方式。这就说明了,简单的遍历不能够挖掘出问题的本质,就要用two pointer.
3. sorting+two pointer, 复杂度o(n^2)。排序配合two pointer,很常用,不然不知道调整那一个pointer。方法是:在每一个位置i处,让这个位置的值等于c,然后在[i+1,n-1]找两个数相加等于0-c,在这个区间用two pointer,根据nums[left]+nums[right]和0-c的关系,决定如何移动指针。
4. 如何取重复?由于给的序列有重复的元素,必须在移动指针的时候判断是否重复。判断重复有三个地方,因为三个元素都需要判断,第一个是在位置i,判断nums[i]==nums[i-1],相等则说明重复;在用two pointer遍历[i+1,n-1],当找到一对相等的数,就要判断left/移动后和移动前是否相等,等则需要继续移动!
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
//sorting+two pointer
int n=nums.size();
vector<vector<int>> res;
vector<int> cur(3,0);
if(n<3) return res;
sort(nums.begin(),nums.end());
for(int i=0;i<n-2;i++){
if(i>0&&nums[i]==nums[i-1]) continue;//去重复
int left=i+1,right=n-1;
int newtarget=0-nums[i];
while(left<right){
int curSum=nums[left]+nums[right];
if(newtarget==curSum){
cur={nums[i],nums[left],nums[right]};
res.push_back(cur);
left++;
right--;
while(left<right&&nums[left-1]==nums[left])//去重复,一般就是skip
left++;
while(left<right&&nums[right+1]==nums[right])//去重复,一般就是skip
right--;
}else if(curSum>newtarget)
right--;
else
left++;
}
}
return res;
}
};