15. 3Sum
在2Sum问题中,可以使用one pass
结合哈希表快速得到问题的答案。但是如果想在3Sum问题中,沿用之前的方式必然要解决重复元素的问题。现在有种可以解决Nsum的思路,基于2Sum的双指针方法。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums){
vector<vector<int>> ans;
int tmp;
sort(nums.begin(),nums.end());
for(int i=0;i<nums.size();++i){
//此时不会漏掉任何元素,且避免重复。如果有重复元素构成答案的话,在第一次判断该元素的时候就会得到答案
while( i!=0 && nums[i-1]==nums[i]) ++i;
int j=i+1,k=nums.size()-1;
for(;j<k;){
tmp=nums[l]+nums[i]+nums[j]+nums[k];
if(tmp == 0){
ans.push_back({nums[i],nums[j],nums[k]});
++j;
//这里因为i是唯一的,j如果此时有重复一定会有重复答案,所以j直接跳过重复元素,同样的如果判断该元素的
//时候答案包括自身,则在第一次的时候,就已经考虑了。
while (j < k && nums[j] == nums[j-1]) ++j;
}
else if(tmp >0)
--k;
else
++j;
}
}
return ans;
}
};
18. 4Sum
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> ans;
int tmp;
sort(nums.begin(),nums.end());
//多了一个for循环
for(int l=0;l<nums.size();++l){
while( l!=0 && nums[l-1]==nums[l]) ++l;
for(int i=l+1;i<nums.size();++i){
while( i!=l+1 && nums[i-1]==nums[i]) ++i;
int j=i+1,k=nums.size()-1;
for(;j<k;){
tmp=nums[l]+nums[i]+nums[j]+nums[k]-target;
if(tmp == 0 ){
ans.push_back({nums[l],nums[i],nums[j],nums[k]});
++j;
while (j < k && nums[j] == nums[j-1]) ++j;
}
else if(tmp >0)
--k;
else
++j;
}
}
}
return ans;
}
};
16. 3Sum Closest
倘若题目要求变成最接近target的三个数之和(或者三个数,此时多增加些变量而已),那么只需要在3Sum的解决方案中,用变量跟踪最三数之和最接近target的时候。该算法本质上也是一种遍历算法,复杂度为 O ( n 2 ) O(n^2) O(n2)。
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
int ans1=0xfffff,tmp,ans2;
sort(nums.begin(),nums.end());
for(int i=0;i<nums.size();i++){
while( i!=0 && nums[i-1]==nums[i]) i++;
for(int j=i+1,k=nums.size()-1;j<k;){
tmp=nums[i]+nums[j]+nums[k]-target;
if(tmp == 0 )
return target;
//注意abs函数在最小负数的情况下,还是返回该最小负数。
if(ans1>abs(tmp)){
ans1=abs(tmp);
ans2=tmp+target;
}
if(tmp >0)
k--;
else
j++;
}
}
return ans2;
}
};
小结
10-20题总结完毕,并非完整的记录了每一个题,而是选取了一些比较好的题。本文总结了SUM系列问题的求法,该方法为双指针法,能够将时间复杂度降次。特别的,11题Container With Most Water也采用了双指针方法。可以发现,双指针法需要问题性质的满足情况来决定递增哪一个指针,每次只递增一个指针达到优化时间复杂度的效果。