题目:给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
二重遍历的常用化简套路:双指针,用大小关系找出必然的移动规律,通过该规律化简算法。经常 遍历左指针,而右指针作为上限在左指针右移的过程中变化,从而达到O(n)的效果。
双指针常用错指南:while或者for循环出来时两个指针是重和的,出来后如果要处理数据会出现重和的可能。
多重数组遍历的常见易错点:题目要求各个遍历的数之间可以重复吗?如果不能重复,又如何处理所给数组中有重复数的情况呢?可以通过在遍历时与前面的数比较了实现。
分析: 三个数在数组中进行查找,一个循环不变,另外两个数的遍历可以使用双指针(因为三个数中间的大小关系比较紧密)来降低时间复杂度。
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
vector<vector<int>> threeSum(vector<int>& nums){
int total = nums.size();
vector<vector<int>> res;
if(total < 3){
return res;
}
sort(nums.begin(), nums.end());
for (int i = 0; i < total; i++){
if (i > 0 && nums[i] == nums[i-1]){
continue;//如何跳过重复的数字
}
if(nums[i]>0){
break;
}
int end = total -1;
for (int j = i + 1; j < end; j++){
//双指针,遍历左边, 则每种情况只能变化右边, 有点像动态规划,可以先定下来可以这样做事对的
//循环其实也可以进行假设我的这个函数前后都是对的,然后设计中间步骤,类似于递归,动态规划
//由于在第二各遍历过程中,两个数中间的大小联系比较突出, 可以考虑用双指针进行简化遍历查找结果
if(j > i+1 && nums[j] == nums[j-1]){
continue;
}
while(end > j && nums[j]+nums[end]+nums[i] > 0){
end--;
}
//这种while或者for循环套--的最后结果可能是会两者重和, 注意
//如果要处理这些后面的数据, 注意考虑到重和的情况
if(end == j){
break;
}
if(nums[i]+nums[j]+nums[end] == 0){
static vector<int> tempRes;
tempRes.push_back(nums[i]);
tempRes.push_back(nums[j]);
tempRes.push_back(nums[end]);
res.push_back(tempRes);
}
}
}
return res;
}
int main(void){
vector<int> a;
int b[] = {-1, 0, 1, 2, -1, -4};
a.insert(a.begin(), b, b + 6);
vector<vector<int>> res = threeSum(a);
for (int i = 0; i < res.size(); i++){
printf("[%d, %d, %d], ", res[i][0], res[i][1], res[i][2]);
}
return 0;
}