题目:
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
解析:
1. 首先考虑特殊情况,因为答案是一个三元组,如果初始的数组本身长度就小于3,那直接不用考虑。
2. 对数组进行排序,如果排序后的数组第一个数字已经大于0了,那也不用考虑了
3. 接下来就是最一般的情况,通过两个指针left,right分别指向数组的两端,当left>=right时候退出
大致的逻辑如下:
(1)选定nums[i],令left=i+1,right=nums.size()-1
(2)然后比较nums[i] + nums[left] + nums[j] 的大小:
如果大于0,说明右边的数字大了,则right--
如果小于0,说明左边的数字小了,则left++
如果等于0,说明刚好,保存这三个数字,并且为了保证不出现重复的情况,再判断left后面的,和right左边的有没有重复,如果有重复的话直接跳过
(3)第(2)步骤中对三元组里面的第二个数字和第三个数字是否重复进行了判断,并没有对三元组里面第一个数值进行判断,因此在这里需要对第一个数字进行判断。
具体的过程参照代码:
1 class Solution { 2 public: 3 vector<vector<int>> threeSum(vector<int>& nums) { 4 vector<vector<int>> res; 5 if(nums.size()<3) return res; //如果数组长度小于3直接返回空 6 sort(nums.begin(),nums.end()); //对数组先进行一个排序 7 if(nums[0]>0) return res; //如果排序后的数组第一个大于0,直接退出 8 for(int i=0;i<nums.size();i++){ 9 if(nums[i]>0) break; //如果三个排序好的元素第一个大于0,那么后面的都不需要做了,直接退出 10 int left=i+1, right=nums.size()-1; 11 while(left<right){ 12 //这里一定要用if,else if,else,如果都用if的话,会出现重复判断的情况,有可能会出错 13 if(nums[i]+nums[left]+nums[right]>0) right--; 14 else if(nums[i]+nums[left]+nums[right]<0) left++; 15 else{ 16 res.push_back({nums[i],nums[left],nums[right]}); 17 //如果当前选中的left和right中,还有重复的,就继续跳过,避免出现重复的三元组 18 while(left<right && nums[left]==nums[left+1]) left++; 19 while(left<right && nums[right]==nums[right-1]) right--; 20 left++; 21 right--; 22 } 23 } 24 while(i+1<nums.size() && nums[i]==nums[i+1]) i++; //如果所选的第一个元素后面也有重复的,直接跳到下一个重复的位置 25 } 26 return res; 27 } 28 };