力扣刷题日记7---剑指 Offer II 007. 数组中和为 0 的三个数
给定一个包含 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
思路1:暴力解法
三层 for 循环寻找所有可能的答案,但是要注意去重。代码如下:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> ret;
sort(nums.begin(), nums.end());
int size = nums.size();
for(int i = 0; i < size - 2; ++i){
if(i != 0 && nums[i] == nums[i - 1])
continue;
if(nums[i] > 0)
return ret;
for(int j = i + 1; j < size - 1; ++j){
for(int k = size - 1; k > j; --k){
if(nums[i] + nums[j] + nums[k] == 0){
ret.push_back({nums[i], nums[j], nums[k]});
int tmp = nums[j];
while(tmp == nums[j] && j < k)
j++;
}
}
}
}
return ret;
}
};
时间复杂度:O(n3),会超时;空间复杂度:O(1)。
思路2:排序 + 双指针
首先对给定数组进行排序,然后固定数组的一个元素,用双指针寻找其余两个数,并注意去重,相当于上一题的进阶版。代码如下:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> ret;
sort(nums.begin(), nums.end());
int size = nums.size();
for(int i = 0; i < size - 2; ++i){
//防止第一个元素重复
if(i != 0 && nums[i] == nums[i - 1])
continue;
//第一个元素大于 0, 后边所有元素的组合一定大于 0, 可以直接退出循环
if(nums[i] > 0)
break;
int tar = -nums[i];
int left = i + 1, right = size - 1; //上一题的双指针解法
int cur = 0;
while(left < right){
cur = nums[left] + nums[right];
if(cur == tar){
ret.push_back({nums[i], nums[left], nums[right]});
int tmp = nums[left];
while(tmp == nums[left] && left < right) //防止第二个元素 nums[left] 重复
left++;
}
else
cur > tar ? right-- : left++;
}
}
return ret;
}
};
时间复杂度:O(n2);空间复杂度:O(1)。