15. 三数之和(中等)
给你一个包含 n
个整数的数组 nums
,判断 nums
中是否存在三个元素 *a,b,c ,*使得 a + b + c = 0 ?请你找出所有和为 0
且不重复的三元组。
**注意:**答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
示例 2:
输入:nums = []
输出:[]
示例 3:
输入:nums = [0]
输出:[]
思路:排序+双指针
-
排序: 先将给定 nums 排序,复杂度为
O(NlogN)
。 -
双指针法思路: 固定 3 个指针中最左(最小)数字的指针 k,双指针 i,j 分设在数组索引
(k, len(nums))
两端,通过双指针交替向中间移动,记录对于每个固定指针 k 的所有满足nums[k] + nums[i] + nums[j] == 0
的 i,j 组合:- 当 nums[k] > 0 时直接break跳出:因为
nums[j] >= nums[i] >= nums[k] > 0
,即 3 个数字都大于 0 ,在此固定指针 k 之后不可能再找到结果了。 - 当 k > 0且
nums[k] == nums[k - 1]
时即跳过此元素nums[k]:因为已经将 nums[k - 1] 的所有组合加入到结果中,本次双指针搜索只会得到重复组合。 - i,j 分设在数组索引
(k, len(nums))
两端,当i < j时循环计算s = nums[k] + nums[i] + nums[j]
,并按照以下规则执行双指针移动:- 当s < 0时,i += 1并跳过所有重复的nums[i];
- 当s > 0时,j -= 1并跳过所有重复的nums[j];
- 当s == 0时,记录组合[k, i, j]至res,执行i += 1和j -= 1并跳过所有重复的nums[i]和nums[j],防止记录到重复组合。
- 当 nums[k] > 0 时直接break跳出:因为
-
复杂度分析:
- 时间复杂度 O(N^2):其中固定指针k循环复杂度 O(N),双指针 i,j 复杂度O(N)。
- 空间复杂度 O(1):指针使用常数大小的额外空间。
(1)C++
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
vector<int> temp(3);
int m = nums.size();
sort(nums.begin(),nums.end());
for(int k=0;k<m-2;k++){
if(nums[k]>0) break;
if(k>0 && nums[k]==nums[k-1]) continue;
int i=k+1 , j=m-1;
while(i<j){
int s =nums[k]+nums[i]+nums[j];
if(s==0){
temp[0]=nums[k];
temp[1]=nums[i];
temp[2]=nums[j];
res.emplace_back(temp);
i++;
j--;
while(i<j && nums[i]==nums[i-1]) i++;
while(i<j && nums[j]==nums[j+1]) j--;
}
else if(s>0){
j--;
while(i<j && nums[j]==nums[j+1]) j--;
}
else{
i++;
while(i<j && nums[i]==nums[i-1]) i++;
}
}
}
return res;
}
};
(2)python
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
m = len(nums)
res = []
nums.sort()
for k in range(m-2):
if nums[k]>0:
break
if k>0 and nums[k]==nums[k-1]:
continue
i = k+1
j = m-1
while(i<j):
if i>k+1 and nums[i]==nums[i-1]:
i+=1
continue
if j<m-1 and nums[j]==nums[j+1]:
j-=1
continue
s = nums[k]+nums[i]+nums[j]
if s==0:
res.append([nums[k],nums[i],nums[j]])
i+=1
j-=1
elif s>0:
j-=1
else:
i+=1
return res