给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/3sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
排序 + 双指针
本题的难点在于如何去除重复解。
算法流程:
特
判
,
对
于
数
组
长
度
n
,
如
果
数
组
为
n
u
l
l
或
者
数
组
长
度
小
于
3
,
返
回
[
]
。
对
数
组
进
行
排
序
。
遍
历
排
序
后
数
组
:
若
n
u
m
s
[
i
]
>
0
:
因
为
已
经
排
序
好
,
所
以
后
面
不
可
能
有
三
个
数
加
和
等
于
0
,
直
接
返
回
结
果
。
对
于
重
复
元
素
:
跳
过
,
避
免
出
现
重
复
解
令
左
指
针
L
=
i
+
1
,
右
指
针
R
=
n
−
1
,
当
L
<
R
时
,
执
行
循
环
:
当
n
u
m
s
[
i
]
+
n
u
m
s
[
L
]
+
n
u
m
s
[
R
]
=
=
0
,
执
行
循
环
,
判
断
左
界
和
右
界
是
否
和
下
一
位
置
重
复
,
去
除
重
复
解
。
并
同
时
将
L
,
R
移
到
下
一
位
置
,
寻
找
新
的
解
若
和
大
于
0
,
说
明
n
u
m
s
[
R
]
太
大
,
R
左
移
若
和
小
于
0
,
说
明
n
u
m
s
[
L
]
太
小
,
L
右
移
特判,对于数组长度 n,如果数组为 null或者数组长度小于 3,返回[]。 对数组进行排序。 遍历排序后数组: 若 nums[i]>0 :因为已经排序好,所以后面不可能有三个数加和等于 0,直接返回结果。 对于重复元素:跳过,避免出现重复解 令左指针 L=i+1,右指针 R=n-1,当 L<R 时,执行循环: 当 nums[i]+nums[L]+nums[R]==0,执行循环,判断左界和右界是否和下一位置重复,去除重复解。并同时将 L,R 移到下一位置,寻找新的解 若和大于 0,说明 nums[R]太大,R左移 若和小于 0,说明 nums[L] 太小,L右移
特判,对于数组长度n,如果数组为null或者数组长度小于3,返回[]。对数组进行排序。遍历排序后数组:若nums[i]>0:因为已经排序好,所以后面不可能有三个数加和等于0,直接返回结果。对于重复元素:跳过,避免出现重复解令左指针L=i+1,右指针R=n−1,当L<R时,执行循环:当nums[i]+nums[L]+nums[R]==0,执行循环,判断左界和右界是否和下一位置重复,去除重复解。并同时将L,R移到下一位置,寻找新的解若和大于0,说明nums[R]太大,R左移若和小于0,说明nums[L]太小,L右移
复杂度分析
时间复杂度:
O
(
n
2
)
O\left(n^{2}\right)
O(n2),数组排序
O
(
N
log
N
)
O(N \log N)
O(NlogN),遍历数组
O
(
n
)
O\left(n\right)
O(n),双指针遍历
O
(
n
)
O\left(n\right)
O(n),总体
O
(
N
log
N
)
+
O
(
n
)
∗
O
(
n
)
,
O
(
n
2
)
O(N \log N)+O\left(n\right)*O\left(n\right),O\left(n^{2}\right)
O(NlogN)+O(n)∗O(n),O(n2)
空间复杂度:
O
(
1
)
O(1)
O(1)
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> ans;
int n = nums.size();
sort(nums.begin(),nums.end());
int l,r;
for(int i = 0;i < n;i++)
{
if(nums[i]>0)break;
if( i > 0 && nums[i]==nums[i-1]) continue;
l = i+1;
r = n-1;
while(l < r)
{
if(nums[i]+nums[l]+nums[r] == 0)
{
vector<int> s;
s.push_back(nums[i]);
s.push_back(nums[l]);
s.push_back(nums[r]);
ans.push_back(s);
while(l < r && nums[l]==nums[l+1])
{
l += 1;
}
while(l < r && nums[r]==nums[r-1])
{
r -= 1;
}
l += 1;
r -= 1;
}
else if(nums[i]+nums[l]+nums[r] > 0)
{
r -= 1;
}
else
{
l += 1;
}
}
}
return ans;
}
};