排序+双指针
首先对整个数组升序排序,便于对结果去重. 朴素算法是暴力枚举数组中的三个位置 (i,j,k),i<j<k
,使得 nums[i]+nums[j]+nums[k]=0
,复杂度为
O
(
n
3
)
O(n^3)
O(n3).
利用双指针算法进行优化,仍然枚举待选取的第一个数 nums[pos]
,然后在 [pos+1,n-1]
中找到两个下标 (le,ri),le<ri
使得 nums[pos]+nums[le]+nums[ri]=0
即可满足要求,算法流程如下:
- 如果
n<3
或数组内元素全部为正或全部为负,答案为空. - 对原数组升序排序.
- 遍历排序后的数组:
- 若
nums[pos]>0
,后面的元素一定也大于 0,因此不可能再有三个数相加和为 0,直接返回结果. - 若
nums[pos-1]=nums[pos]
,直接跳过,避免重复解. - 令左指针
le=pos+1
,右指针ri=n-1
,若le<ri
,则执行循环:nums[pos]+nums[le]+nums[ri]=0
,将这个三元组加入答案中,为了避免记录重复结果,将le
和ri
分别移动到下一处与当前值不相等的位置,继续寻找新的解.- 若
nums[pos]+nums[le]+nums[ri]>0
,将ri
左移. - 若
nums[pos]+nums[le]+nums[ri]<0
,将le
右移.
- 若
左指针 le
只向右移动,右指针 ri
只向左移动,因此总体时间复杂度为
O
(
n
2
)
O(n^2)
O(n2).
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> ans;
int len=nums.size();
sort(nums.begin(),nums.end());
if(len<3 || nums[0]>0 || nums[len-1]<0) return {};
for(int pos=0;pos<len;++pos){
if(nums[pos]>0) break;
if(pos>0 && nums[pos-1]==nums[pos]) continue;
int val=-nums[pos];
int le=pos+1,ri=len-1;
while(le<ri){
if(nums[le]+nums[ri]==val){
ans.push_back({nums[pos],nums[le],nums[ri]});
while(le<ri && nums[le+1]==nums[le]) ++le;
while(le<ri && nums[ri-1]==nums[ri]) --ri;
++le;--ri;
}
else{
if(nums[le]+nums[ri]<val) ++le;
else --ri;
}
}
}
return ans;
}
};
个人 LeetCode 代码仓库地址:MyLeetCode,记录刷题成长之路,欢迎各位小伙伴们多多 star ~