Leetcode 15 -- 双指针
题目描述
思路
先不考虑重复的问题。从暴力出发,我们需要使用三重循环,会超速。
对于数组循环的优化问题,双指针很常用。
双指针(又称为快慢指针)可以将一个二重循环优化为一重,因此我们可以用双指针优化。
我们可以以此枚举每一个点作为第一个数,从后面寻找第二个和第三个数。
关于去重:
首先不管三七二十一,先排序!
首先要知道,什么时候会发生重复!
参考回溯中树层去重的例子,当一个集合的子集相同的时候,后面就可能出现重复。
因此,我们的目标是消除重复的子集。
这和树层去重基本类似:if(i > 0 && nums[i] == nums[i - 1]) continue
当一个数和前一个数相同的时候,如果前一个数没有选,我们说此时子集重复了。但这里我们并没有判断前一个数有没有选。
这是因为不需要判断,因为当前的nums[i]是起点,之前的数肯定没选。
代码
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int n = nums.size();
if(n < 3) return {};
sort(nums.begin(), nums.end());
// for(auto &x : nums) cout << x << ' ';
cout << endl;
vector<vector<int>> res;
for(int i = 0; i < n; i ++ ) {
if(nums[i] > 0) break;
if(i > 0 && nums[i] == nums[i - 1]) continue; // 子集:{x..},{x..}
int l = i + 1, r = n - 1;
while(l < r) { // 不能 l<=r, 否则他们就是同一个数,而我们需要两个数
if(nums[l] + nums[r] + nums[i] > 0) {
while(r > l && nums[l] + nums[r] + nums[i] > 0) r -- ;
}
else if(nums[l] + nums[r] + nums[i] < 0) {
while(r > l && nums[l] + nums[r] + nums[i] < 0) l ++ ;
}
else { //if(nums[l] + nums[r] + nums[i] == 0)
res.push_back(vector<int>{nums[i], nums[l], nums[r]});
l ++ , r -- ;
while(l < r && nums[l] == nums[l - 1]) l ++ ; // 子集:{x,y,z},{x,y,z},y重复
while(l < r && nums[r] == nums[r + 1]) r -- ; // 子集:{x,y,z},{x,y,z},z重复
}
}
}
return res;
}
};