双指针最基础的题目是一个区间里找两个数字的和等于Target。首先将区间从小到大排序。接下来只要一个le指针,一个ri指针,分别从区间左右边界往中间推进即可。复杂度是排序的nlogn。
下面几道题都是一个区间里找三个数字的和满足xx条件的。这个题目的做法首先还是先排序。之后先固定一个数字,然后在该数字的右侧区间内重新使用之前找两个数字的和的算法。 即i 从0到n-1,j 从i+1开始增加,k 从n-1开始减小直到j和k碰撞。这样的复杂度是n平方。外层i从0到n-1是O(n),内层从i+1到n-1也是O(n)。
15
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
if(nums.empty()){return vector<vector<int>>();}
sort(nums.begin(),nums.end());
vector<vector<int>> res;
int n=nums.size();
for(int i=0;i<n;++i){
if(i>0 and nums[i-1]==nums[i]){continue;}
int j=i+1,k=n-1;
while(j<k){
while(j<k and j>i+1 and nums[j]==nums[j-1]){
++j;
}
while(j<k and k<n-1 and nums[k]==nums[k+1]){
--k;
}
if(j>=k){break;}
if(nums[i]+nums[j]+nums[k]>0){
--k;
}
else if(nums[i]+nums[j]+nums[k]<0){
++j;
}
else{
res.push_back({nums[i],nums[j],nums[k]});
++j,--k;
}
}
}
return res;
}
};
16
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
int n=nums.size();
if(n<3){return 0;}
sort(nums.begin(),nums.end());
int min_distance=INT_MAX,temp,sum=0;
for(int i=0;i<n;++i){
if(i>0 and nums[i]==nums[i-1]){continue;}
int j=i+1,k=n-1;
while(j<k){
if((temp=nums[i]+nums[j]+nums[k]-target)>0){
if(temp<min_distance){
min_distance=temp;
sum=temp+target;
}
--k;
while(j<k and nums[k]==nums[k+1]){
--k;
}
}
else if(temp<0){
if(-temp<min_distance){
min_distance=-temp;
sum=temp+target;
}
++j;
while(j<k and nums[j-1]==nums[j]){
++j;
}
}
else{
return target;
}
}
}
return sum;
}
};
259
class Solution {
public:
int threeSumSmaller(vector<int>& nums, int target) {
int N=nums.size(),res=0;
sort(nums.begin(),nums.end());
for(int i=0;i<N-2;++i){
int j=i+1,k=N-1;
while(j<k){
if(nums[i]+nums[j]+nums[k]<target){
res+=k-j;
j++;
}
else{
k--;
}
}
}
return res;
}
};