首页 > 其他分享 >力扣:三数之和(左右双指针思路+动画演示+代码实现)

力扣:三数之和(左右双指针思路+动画演示+代码实现)

时间:2024-07-25 13:00:46浏览次数:13  
标签:slow nums 三数 左右双 fast 力扣 result 指针

题目

在这里插入图片描述

①双指针思路(双指针匹配方式,还不涉及去重 )

1.需要的变量个数(三个变量,双指针作为其中两个)

left、right已经两个变量,表示两个数。
题目求三数之和,只需要另外一个变量 i 即可!

所以一共是 nums[i]、nums[left]、nums[right]。存储满足条件的这三个值

2.双指针工作原理

三数之和:(三个变量之和)

①和等于0,加入结果集,并且slow也要右移
②和小于0,slow右移(无法移动就i右移)
③和大于0,fast左移

3.必须对原数组进行排序

双指针的工作原理,特别像二分查找。都是依据原数组有序性的!
所以原数组必须先进行排序才能使用双指针法

4.动画理解双指针工作方式(含去重,图里的其实是set容器去重方式)

<iframe allowfullscreen="true" data-mediaembed="csdn" frameborder="0" id="ad1JTctn-1721391579061" src="https://live.csdn.net/v/embed/410921"></iframe>

三数之和(双指针法思路)

②代码实现建议(含去重思路两种,主要介绍双指针去重)

1.不要一开始就同时考虑匹配三数之和、去重。这两种功能

同时考虑这两种操作会导致:

逻辑复杂,难以实现,逻辑出错率极高(本人亲身体验)

2.先实现"三数之和结果集的存储"功能

class Solution {
public:
	vector<vector<int>>result;
    //三数之和
    //第一点 
    //单次匹配思路:找满足条件的 nums[i]、nums[left]、 nums[right]。//i<left<right
    
    //第二点
	//必须先查找完成之后,在考虑去重操作,不要两个操作一起考虑,很容易逻辑混乱,导致做不出! 
    vector<vector<int>> threeSum(vector<int>& nums)
    {
        //双指针解决本问题需要排序
		//为什么要排序:双指针工作原理(类似二分查找,需要有序性) 
		sort(nums.begin(),nums.end());
		
		result.clear();
		
		for(int i = 0;i<nums.size()-2;i++){
			if(nums[i]>0)return result;//剪枝操作(第一个元素最小,如果都是正数,正数相加只会更大)
			int slow = i+1;
			int fast = nums.size()-1;
			while(slow<fast){//这里体现左右双指针,所以不会是i在left,right区间内 
				
				if(nums[i]+nums[slow]+nums[fast]==0){//满足三数之和的情况 
					result.push_back({nums[i],nums[slow],nums[fast]}); 
					slow++;
				}
				
				else if(nums[i]+nums[slow]+nums[fast]>0){ fast--;} //和太大的情况}
				
				else{ slow++; }//和太小的情况 
				
			}
		}
        return result;
    }
};

3.再实现"结果集去重"功能

Ⅰ:set容器去重(效率会比较低)

比较方便实现,代码几没有改动

本来是使用二维数组存储,改成set<vector<int>>存储即可!最后返回值再改成二维数组

Ⅱ:利用双指针去重(效率比较高)

1.需要积累经验,第一次写不出很正常。

所有变量都要去重(本题三数之和,三个变量都要去重)

2.收集结果集之后再去重

反证法如下:

进行 nums[i]的去重。必须是收集完结果集之后再去重。
举例:-2,-2,-2,0,2,2,4
结果集含 {-2,-2,4}。如果先去重,一定就排除了nums[slow]==nums[i]的情况(结果集又包含这种情况)

3.补充:(如果说法有误,虚心更正哈)

了解即可,代码随想录是先对 i 进行去重,但左右指针去重是收录结果后!
(而我把三个变量都统一成收录结果后去重了)

其实如果去重的方式不影响后续的值(代码随想录写法:i去重不影响slow)那么就可以先去重

③具体代码实现(两种版本,注释也很详细)

1.第一种版本(set容器,效率比较低,但是很好实现,代码几乎没有变动)

修改地方只有四处。

class Solution {
public:
	set<vector<int>>result;//第一处修改
	
    //三数之和
    //第一点 
    //单次匹配思路:找满足条件的 nums[i]、nums[left]、 nums[right]。//i<left<right
    
    //第二点
	//必须先查找完成之后,在考虑去重操作,不要两个操作一起考虑,很容易逻辑混乱,导致做不出! 
    vector<vector<int>> threeSum(vector<int>& nums)
    {
        //双指针解决本问题需要排序
		//为什么要排序:双指针工作原理(类似二分查找,需要有序性) 
		sort(nums.begin(),nums.end());
		
		result.clear();
		
		
		for(int i = 0;i<nums.size()-2;i++){
			//第二处修改
			if(nums[i]>0)return {result.begin(),result.end()};//剪枝操作(第一个元素最小,如果都是正数,正数相加只会更大)
			int slow = i+1;
			int fast = nums.size()-1;
			while(slow<fast){//这里体现左右双指针,所以不会是i在left,right区间内 
				
				if(nums[i]+nums[slow]+nums[fast]==0){//满足三数之和的情况 
					result.insert({nums[i],nums[slow],nums[fast]}); //第三处修改,set容器使用insert
					slow++;
				}
				
				else if(nums[i]+nums[slow]+nums[fast]>0){ fast--; }//和太大的情况}
				
				else{ slow++; }//和太小的情况 
				
			}
		}
        return {result.begin(),result.end()};//第四处修改
    }
};

2.第二种版本(双指针去重,效率高,满满的经验!)

class Solution {
public:
	
    //三数之和
    //第一点 
    //单次匹配思路:找满足条件的 nums[i]、nums[left]、 nums[right]。//i<left<right
    
    //第二点
	//必须先查找完成之后,在考虑去重操作,不要两个操作一起考虑,很容易逻辑混乱,导致做不出! 
    vector<vector<int>> threeSum(vector<int>& nums)
    {
    	vector<vector<int>>result;
    	
        //双指针解决本问题需要排序
		//为什么要排序:双指针工作原理(类似二分查找,需要有序性) 
		sort(nums.begin(),nums.end());
		
		
		for(int i = 0;i<nums.size()-2;i++){
			if(nums[i]>0)return result;//剪枝操作(第一个元素最小,如果都是正数,正数相加只会更大) 
            int slow = i+1;
			int fast = nums.size()-1;
			while(slow<fast){//这里体现左右双指针,所以不会是i在left,right区间内 
				
				if(nums[i]+nums[slow]+nums[fast]==0){//满足三数之和的情况 
					result.push_back({nums[i],nums[slow],nums[fast]}); 

					while(slow<fast&&nums[slow]==nums[slow+1]){//slow去重
						slow++;	
					}
					
					while(slow<fast&&nums[fast]==nums[fast-1]){//fast去重 
						fast--;
					}
					
					slow++;
                    fast--;//不写fast--也行!
				}
		
				else if(nums[i]+nums[slow]+nums[fast]>0){ fast--;} //和太大的情况}
				
				else{ slow++; }//和太小的情况 
			}
			
			//进行 nums[i]的去重。必须是收集完结果集之后再去重。
			//举例:-2,-2,-2,0,2,2,4
			//结果集含 -2,-2,4。没办法去重后再收集结果,因为nums[slow] == nums[i]//往这个方面思考就知道了! 
			while(nums[i]==nums[i+1]&&i<nums.size()-2){
				i++;
			}//还有一种去重方式 if(nums[i]==nums[i-1])//具体看:https://programmercarl.com/0015.%E4%B8%89%E6%95%B0%E4%B9%8B%E5%92%8C.html#%E6%80%9D%E8%B7%AF
			
		}
        return result;
    }
};

标签:slow,nums,三数,左右双,fast,力扣,result,指针
From: https://blog.csdn.net/kchick/article/details/140558170

相关文章

  • 算法力扣刷题记录 五十九【450.删除二叉搜索树中的节点】
    前言记录五十八【701.二叉搜索树中的插入操作】保证插的新节点在叶子节点的位置,如此实现递归。那么【450.删除二叉搜索树中的节点】删除如何实现?还有简单的方法吗?一、题目阅读给定一个二叉搜索树的根节点root和一个值key,删除二叉搜索树中的key对应的节点,并保证二......
  • 算法力扣刷题记录 五十七【236. 二叉树的最近公共祖先】和【235. 二叉搜索树的最近公
    前言公共祖先解决。二叉树和二叉搜索树条件下的最近公共祖先。二叉树篇继续。一、【236.二叉树的最近公共祖先】题目阅读给定一个二叉树,找到该树中两个指定节点的最近公共祖先。百度百科中最近公共祖先的定义为:“对于有根树T的两个节点p、q,最近公共祖先表示为一......
  • 力扣-图
    目录图200-岛屿数量-中等130-被围绕的区域-中等133-克隆图-中等399-除法求值-中等-反复看207-课程表-中等210-课程表II-中等909-蛇梯棋-中等-变态433-最小基因变化-中等-BT127-单词接龙-中等208-实现Trie(前缀树)-中等212-单词搜索-困难211-添加与搜索单词-数据结构涉及-中等BFS......
  • 力扣1456. 定长子串中元音的最大数目(java)
     题目描述示例思路看到“定长子串”时,我们容易联想到用滑动数组来实现这个算法。滑动数组允许我们在每次移动窗口时,只需增加新元素并减去旧元素的计数,而不必重新计算整个窗口的内容,相对于其他复杂的算法来说,实现起来更为直观和简单解题方法1.首先创建isVomel方法......
  • 力扣高频SQL 50题(基础版)第九题
    文章目录力扣高频SQL50题(基础版)第九题197.上升的温度题目说明思路分析实现过程准备数据实现方式结果截图总结力扣高频SQL50题(基础版)第九题197.上升的温度题目说明Weather±--------------±--------+|ColumnName|Type|±--------------±--------+......
  • 力扣高频SQL 50题(基础版)第八题
    文章目录力扣高频SQL50题(基础版)第八题1581.进店却未进行过交易的顾客题目说明思路分析实现过程准备数据:实现方式:结果截图:总结:力扣高频SQL50题(基础版)第八题1581.进店却未进行过交易的顾客题目说明表:Visits±------------±--------+|ColumnName|Type|......
  • 【算法专题】双指针算法之611. 有效三角形的个数(力扣)
    欢迎来到CILMY23的博客......
  • 【算法专题】双指针算法之LCR 179. 查找总价格为目标值的两个商品(力扣)
     欢迎来到CILMY23的博客......
  • 代码随想录哈希表第二天:四数相加2、三数之和、四数之和、赎金信
    详细可移步个人代码随想录打卡四数相加使用2次,2层for循环。即可确定和值,然后使用一个map来记录第一个for循环的值,再第二次for循环中找,并记录次数即可。代码如下:importjava.util.HashMap;importjava.util.Map;classSolution{publicintfourSumCount(int[]n......
  • 代码随想录算法训练营Day7 | Leetcode 454 四数相加Ⅱ Leetcode 383 赎金信 Leetcode
    前言今天的四道题目稍稍有点难度,需要理解和反复记忆才行。四数相加类比于两数之和,赎金信类比于异位词,三数之和和四数之和自成体系,可以推广到n数之和。Leetcode454四数相加Ⅱ题目链接:454.四数相加II-力扣(LeetCode)代码随想录题解:代码随想录(programmercarl.com)思路:......