最近开始刷力扣题,想给自己觉得对自己有启发的题目写博客,记录自己的成长。
题目分析
题目是这样的,给定一个数组,求数组中三个数加起来和为0的数,特别注意,不能包含重复的元组。首先分析题目,为了排除重复,我们需要对数组进行排序,因为排完序之后,C++中algorithm中sort()复杂度围为O(nlogn)可以忽略,如果碰到一样的值就可以直接跳过。给一个简单的例子。[-1,0,1,2,-1,-4],排完序之后[-4,-1,-1,0,1,2],比如首指针碰到第一个-1,找到两个元组[-1,-1,2],[-1,0,1], 而后碰到第二个-1就直接跳过不需要进行查找,因为这样就避免了重复。
解决思路 (排序+三指针)
针对排完序的数组,我们设置k为遍历数组指针,i,j为寻找匹配项的指针,一个从前往后,一个从后往前,每次i等于k+1,j等于数组长度-1:
- 如果nums[i]+num[j]+num[k]<0,则说明三个数和小了,则移动i,i++;
- 如果nums[i]+num[j]+num[k]>0,则说明三个数和大了,则移动j,j++;
- 否则,三数和等于=0,为我们需要的元组,记录nums[i],num[j],num[k],然后将i,j指针移到与当前nums[i],num[j]不同的下标。
代码
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
sort(nums.begin(),nums.end());
if(nums.size()<3) //数组长度小于3,不存在三数之和等于0;
return res;
for(int k=0;k<=nums.size()-3;k++) //k为遍历数组指针,后面有i,j,所以K只用遍历到nums.size()-3
{
if(nums[k]>0) //当前最小值都大于0,不存在三个正数之和等于0
break;
if(k>0 && nums[k]==nums[k-1]) continue; //如果当前值与前面的值相等直接跳过,避免出现重复元组
int i=k+1;
int j=nums.size()-1;
while(i<j)
{
if(nums[i]+nums[j]+nums[k]>0)
j--;
else if(nums[i]+nums[j]+nums[k]<0)
i++;
else{
res.push_back(vector<int>{nums[k],nums[i],nums[j]});
while(i<j&&nums[i]==nums[i+1])
i++;
while(i<j&&nums[j]==nums[j-1])
j--;
i++;
j--;
}
}
}
return res;
}
};
最后结果: