题目来源:https://leetcode-cn.com/problems/3sum/
题目描述
给你一个包含 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]
输出:[]
提示:
0 <= nums.length <= 3000
-105 <= nums[i] <= 105
题目大意
- 给定一个数组,返回所有数组中三个数相加等于0的集合且不重复,对于不重复问题,可以思考数组在什么情况下寻找满足条件的数组可以避免重复问题,易知将数组进行排序是为了方便结果集中的所有子集内都遵循一定的单调性
- 暴力循环O(n^3),在数组长度∈[0,3000]中,是有可能的超时的
- first和second选择不同的元素,保证了不会去到重复的元素枚举,second < third保证了second和third不会出现交换重复的情况
[ − 1 , 1 , 0 ] [ 1 , − 1 , 0 ] [ 0 , − 1 , 1 ] [-1,1,0] \quad[1,-1,0]\quad[0,-1,1] [−1,1,0][1,−1,0][0,−1,1]
排序+双指针
- 在上述思路中进行深究,对数组从小到大排序过后,在以下式子当中,当确定了a时,以b从下标小逐渐遍历到大,当b是逐渐递增时,满足条件的c是逐渐递减的,即原先所想的遍历b和c所需的时间复杂度O(n^2)就降为了O(n)(b从左往右最多遍历n次,c从右往左最多遍历n次,n为数组的长度),与做滑动窗口类题目的分析差不多
a + b + c = 0 a + b ′ + c ′ = 0 ( i f b ′ ≥ b , T h e n c ′ ≤ c ) \begin{gathered} a+b+c=0\\a+b^{'}+c^{'} = 0\quad(if \quad{b^{'}} ≥b,Then\quad{c{'}≤c}) \end{gathered} a+b+c=0a+b′+c′=0(ifb′≥b,Thenc′≤c) - 注意处理一下相同每移动一个指针时,都需要判断它是否跟前一个元素值相等
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(), nums.end(), less<int>() );
vector<vector<int>> ans;
int len = nums.size();
if(len < 3) return ans;
for(int first = 0 ; first < len ; ++first){
if(first > 0 && nums[first] == nums[first - 1])
continue;
int third = len - 1;
for(int second = first + 1; second < len ; ++second){
if(second > first + 1 && nums[second] == nums[second - 1])
continue;
int target = -(nums[second] + nums[first]);
while(second < third && nums[third] > target)
--third;
if(second == third)
break;
if(nums[third] == target)
ans.push_back({
nums[first], nums[second], nums[third]});
}
}
return ans;
}
};
复杂度分析
- 时间复杂度:O(n^2)。n为数组的长度,a遍历n次,b和c遍历时间复杂度O(n)
- 空间复杂度:O(logn)。n为数组的长度,快速排序所用的平均空间复杂度为O(logn),在最坏的情况下需要进行n-1次递归调用,其空间复杂度为O(n)