小白跟随卡哥刷题第十三天(hash表部分)

一、前言

今天的题目上难度了,确实是让人思考许久,我想这也才是我们需要努力去刷题,提高自己的重要途径吧。又不会的地方大家看看卡哥的讲解,部分难题也会有b站的视频讲解,各位uu可以自己去理解,那么就直接上题吧。

二、题目(力扣第15题—三数之和. - 力扣(LeetCode)

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != 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的机会现在是无限的,最后如果觉得可能有些欠缺,那么就好好看看卡哥的讲解,然后自己重新按着思路,自己写一遍看看可以达到效果吗,我想这是我的一点刷题心得,也是不错的一种思路吧,各位加油,好好刷题,好好生活!!!

  • 25
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值