一、前言
今天的题目上难度了,确实是让人思考许久,我想这也才是我们需要努力去刷题,提高自己的重要途径吧。又不会的地方大家看看卡哥的讲解,部分难题也会有b站的视频讲解,各位uu可以自己去理解,那么就直接上题吧。
二、题目(力扣第15题—三数之和. - 力扣(LeetCode))
给你一个整数数组 nums
,判断是否存在三元组 [nums[i], nums[j], nums[k]]
满足 i != j
、i != k
且 j != k
,同时还满足 nums[i] + nums[j] + nums[k] == 0
。请
你返回所有和为 0
且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4] 输出:[[-1,-1,2],[-1,0,1]] 解释: nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。 nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。 nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。 不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。 注意,输出的顺序和三元组的顺序并不重要。
示例 2:
输入:nums = [0,1,1] 输出:[] 解释:唯一可能的三元组和不为 0 。
示例 3:
输入:nums = [0,0,0] 输出:[[0,0,0]] 解释:唯一可能的三元组和为 0 。
三、题解
对于这个题,卡哥的讲解我先放到这里(代码随想录)。我先说说我对这个题的理解,其实这个题不是很难理解,有点像前面的两数之和(a+b)的加强版,变成了三数之和,两数之和(a+b)的时候我们是用一个循环来控制a的值,再使用find函数来寻找另一个b;那么在三数之和(a+b+c)中我们也可以采用类似的办法,进行两重循环来确定a、b的值,再通过find函数来寻找c的值。但是这个题的另一个难点是结果不可以重复,因此前两个循环时要把a、b可能重复的答案去除,再确定c。(另外卡哥的双指针法对于这个题是最有效的解法,也是我看了讲解以后,觉得是最好的解法)在此我只讲一讲利用hash的办法,双指针法请各位uu去b站看卡哥的讲解即可。
我先把代码放出来
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result;
sort(nums.begin(),nums.end());
for(int i=0;i<nums.size();i++){
if(nums[i]>0){
break;}
if((i>0)&&(nums[i]==nums[i-1])){
continue;}
unordered_set<int> set;
for(int j=i+1;j<nums.size();j++){
if (j > i + 2&& nums[j] == nums[j-1]&& nums[j-1] == nums[j-2]) { // 三元组元素b去重
continue;
}
int c=0-nums[i]-nums[j];
if(set.find(c)!=set.end()){
result.push_back({nums[i],nums[j],c});
set.erase(c);
}
else{
set.insert(nums[j]);
}
}
}
return result;
}
这里先对nums进行排序,因为最后的结果只要返回数值即可,不需要返回数值的下标,因此先进性排序可以省掉一些麻烦,在后面说。然后使用i、j来确定a、b的值(两重循环)但是要注意去掉重复的结果
if(nums[i]>0){//已经排序好了,如果最小的a都大于0,那么三个数一定加起来大于0直接跳过
break;}
if((i>0)&&(nums[i]==nums[i-1])){//这里是对a进行去重
continue;}
还有这里为什么不用nums[i]==nums[i+1]呢,两者看起来并没有区别,但是最重要的区别在这里我举个例子就懂了,比如nums={-1,-1,2}这个也有结果那就是它本身,但是如果判断条件是nums[i]==nums[i+1],这里的结果就会被跳过导致最后的结果是NULL,所以判断去重条件是nums[i]==nums[i-1]。
接着是找第二个数b并且去重,这里对b的去重是类似的,大家可以自己理解。
for(int j=i+1;j<nums.size();j++){
if (j > i + 2&& nums[j] == nums[j-1]&& nums[j-1] == nums[j-2]) { // 三元组元素b去重
continue;
}
接着定义一个set用来找第三个数的,c=0-nums[i]-nums[j],然后是熟悉的find函数,这里有个小细节是当找到c是,存入result数组,并且在set中去掉c已达到去重的目的。
int c=0-nums[i]-nums[j];
if(set.find(c)!=set.end()){
result.push_back({nums[i],nums[j],c});
set.erase(c);//c去重
}
else{
set.insert(nums[j]);
}
四、后记
我想今天遇到的难题,大家应该对思考,多去试试,debug的机会现在是无限的,最后如果觉得可能有些欠缺,那么就好好看看卡哥的讲解,然后自己重新按着思路,自己写一遍看看可以达到效果吗,我想这是我的一点刷题心得,也是不错的一种思路吧,各位加油,好好刷题,好好生活!!!