15. 三数之和
1.双指针法
双指针法后面还有两道题,建议学会本题后,直接尝试做做:
16. 最接近的三数之和
题解:https://blog.csdn.net/Dariuswuhe/article/details/123476607
18. 四数之和
题解:https://blog.csdn.net/Dariuswuhe/article/details/123481072
-
如果采取暴力遍历,需要三重循环,时间复杂度为O(n3);
-
我们这里使用双指针法:虽然有三个数字需要同时遍历,但我们可以利用数组排序后的性质,减小第二和第三个数组的时间复杂度:
-
首先将数组递增排序;
-
指针ind1不断从头到尾遍历,如果碰到nums[ind1]==nums[ind1-1]的情况,说明碰到了重复元素,直接跳过;
-
指针ind2位于ind+1,指针ind3=n-1位于尾部,在每次遍历中,我们只移动ind2和ind3;
-
因为数组是递增的,如果三数之和>0,说明数字太大,就需要将三数之和减小,ind3–;
同理,如果数字太小,三数之和需要增大,ind2++;
-
-
这样,我们在时间复杂度O(n)之内就完成了ind2和ind3的遍历。
-
class Solution { public: vector<vector<int>> threeSum(vector<int>& nums) { vector<vector<int>> result; int n=nums.size(),ind1,ind2,ind3; sort(nums.begin(),nums.end()); if(n<3){return result;} for(int ind1=0;ind1<n;ind1++){ if(nums[ind1]>0) return result; while(ind1>0&&ind1<n-1&&nums[ind1]==nums[ind1-1]){ ind1++; } ind2=ind1+1;//第二个指针从ind+1开始 ind3=n-1;//第三个指针从n-1,最后一个元素开始 while(ind2<ind3){ if(nums[ind1]+nums[ind2]+nums[ind3]>0){ ind3--;//相加结果太大,第三个指针左移以减少整体和 }else if(nums[ind1]+nums[ind2]+nums[ind3]<0){ ind2++;//相加结果太小,第二个指针右移以增加整体和 }else{ vector<int> v{nums[ind1],nums[ind2],nums[ind3]}; result.push_back(v); ind2++;ind3--; while(ind2<ind3&&nums[ind2]==nums[ind2-1]){ ind2++; } while(ind2<ind3&&nums[ind3]==nums[ind3+1]){ ind3--; } //两个指针向中间靠拢,去掉重复的元素 } } } return result; } };
2.set去重
-
本题的答案不能出现重复结果,我们在上面通过相同元素跳过的方式去除了重复结果。
-
但如果一些复杂情况下不能有效分析出去重方式,可以使用STL中的set容器,达到去重的目的,set会将元素自动进行排序、去重,和map一样,是一种关联式容器,实现原理是红黑树。
- 插入:set.insert();
- 使用迭代器遍历 auto it=set.begin();
- 输出元素时加上*, *it;
-
class Solution { public: vector<vector<int>> threeSum(vector<int>& nums) { vector<vector<int>> result; set<vector<int>> set1; int n=nums.size(),ind1,ind2,ind3; sort(nums.begin(),nums.end()); if(n<3){return result;} for(int ind1=0;ind1<n;ind1++){ if(nums[ind1]>0) break; ind2=ind1+1;//第二个指针从ind+1开始 ind3=n-1;//第三个指针从n-1,最后一个元素开始 while(ind2<ind3){ if(nums[ind1]+nums[ind2]+nums[ind3]>0){ ind3--;//相加结果太大,第三个指针左移以减少整体和 }else if(nums[ind1]+nums[ind2]+nums[ind3]<0){ ind2++;//相加结果太小,第二个指针右移以增加整体和 }else{ vector<int> v{nums[ind1],nums[ind2],nums[ind3]}; set1.insert(v); // cout<<"s:"<<set1.size()<<endl; ind2++;ind3--; } } } for(auto it=set1.begin();it!=set1.end();it++){ result.push_back(*it); } return result; } };