题目:
给你一个包含 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
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
暴力求解:
最直接的方法是套三层循环并遍历数组,当有不重复的符合条件的子数组出现时将它加到结果里。这样的时间复杂度是O(n^3)。我们需要对此进行优化。
双指针:
我们可以用双指针来有效的降低时间复杂度。可以将这个问题简化成选一个数,找到另外两个数和它相加等于0.选择这两个数的问题就是两数之和。首先对数组排序,然后遍历数组里每一个数并选做第一个数。随后选择最后一个数作为当前的第三个数,第二个数为第一个数后面的数(如果第一个数的下标是n,那么第二个就是n+1)。这里的第二个和第三个数就是双指针。这样当三者之和不等于0时,我们可以根据条件来挪动左右指针。当和等于0时,将当前数组放入结果,进行去重,往后挪动右指针直到指向的值不等于当前第二个数,往前挪动左指针直到指向的值不等于当前第三个数。随后收缩指针,这样避免重复。最后返回结果。
代码:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(), nums.end());
int n = nums.size();
vector<vector<int>> res;
// iterate through the list
for (int first = 0; first < n; first ++)
{
// check for duplicate
if (first > 0 && nums[first] == nums[first-1])
{
continue;
}
int third = n-1;
int second = first+1;
// find the second and third numbers where sum + first = 0
// two sum part
while (second < third)
{
if (nums[first]+nums[second]+nums[third] > 0)
{
// sum > 0, move right pointer so that sum is smaller
third --;
}
else if (nums[first]+nums[second]+nums[third] < 0)
{
// sum < 0 move left pointer so that sum is larger
second ++;
}
else
{
res.push_back({nums[first],nums[second],nums[third]});
// make sure there is no duplicate combine
while (third > second && nums[second] == nums[second+1])
{
second++;
}
while (third > second && nums[third] == nums[third-1])
{
third--;;
}
// shrink search space
third --;
second ++;
}
}
}
return res;
}
};
时间复杂度: O(n^2): 遍历一遍数组O(n),双指针遍历数组最坏情况O(n),所以是O(n*n)
参考:
https://leetcode-cn.com/problems/3sum/
https://leetcode-cn.com/problems/3sum/comments/
https://leetcode-cn.com/problems/3sum/solution/san-shu-zhi-he-by-leetcode-solution/