【leetcode】双指针算法题
文章目录
- 1.算法思想
- 2.移动零
- 3.复写零
- 方法一
- 方法二
- 4.快乐数
- 5.盛水最多的容器
- 方法一(暴力求解)
- 方法二(左右指针)
- 6.有效三角形的个数
- 方法一(暴力求解)
- 方法二(左右指针)
- 7.两数之和
- 8.三数之和
- 9.四数之和

1.算法思想
常见的双指针有两种形式,⼀种是左右指针,⼀种是快慢指针。
- 左右指针:⼀般用于有序的结构中,也称左右指针。
- 左右指针从两端向中间移动。⼀个指针从最左端开始,另⼀个从最右端开始,然后逐渐往中间逼近。
- 左右指针的终⽌条件⼀般是两个指针相遇或者错开(也可能在循环内部找到结果直接跳出循环),也就是:
left == right (两个指针指向同⼀个位置)
left > right (两个指针错开)
- 快慢指针:⼜称为龟兔赛跑算法,其基本思想就是使⽤两个移动速度不同的指针在数组或链表等序列结构上移动。
这种方法对于处理环形链表或数组非常有用。
其实不单单是环形链表或者是数组,如果研究的问题出现循环往复的情况时,均可考虑使用快慢指针的思想。
快慢指针的实现⽅式有很多种,最常用的⼀种就是:
- 在⼀次循环中,每次让慢的指针向后移动⼀位,而快的指针往后移动两位,实现⼀快⼀慢。
废话不多说,我们来做题。
2.移动零

leetcode 283.移动零
题目要求我们将数组中的0全部移动到数组的末尾,并且其它元素的相对顺序不变,而且不允许开辟额外的数组。
那我们应该如何来解决这一题呢?
算法思路:
在本题中,我们可以⽤⼀个cur 指针来扫描整个数组,另⼀个dest 指针⽤来记录⾮零数序列的最后⼀个位置。
根据cur 在扫描的过程中,遇到的不同情况,分类处理,实现数组的划分。
在cur遍历期间,使[0, dest] 的元素全部都是⾮零元素,[dest + 1, cur - 1] 的元素全是零。
最初,我们不知道非零序列的位置,所以将dest置为-1,cur置为0。cur进行扫描,在扫描过程中:
- 若cur对应元素不为0,cur后移
- 若cur对应元素为0,dest先后移,然后再交换cur与dest,最后cur再后移。

class Solution {
public:void moveZeroes(vector<int>& nums) {int dest = -1;int cur = 0;int n = nums.size();while(cur < n){//cur不为0,交换if(nums[cur] != 0){dest++;swap(nums[dest],nums[cur]);}//cur为0,继续后移cur++;}}
};
这样咱们就过啦。

3.复写零

leetcode 1089.复写零
方法一
先统计数组中0的个数,计算复写后数组的大小,使用reserve为数组重新开新的空间,在新空间上直接进行复写,不存在数组越界问题;在复写完成后,再使用对数组进行缩容,使其空间保持原状。
class Solution {
public:void duplicateZeros(vector<int>& arr) {int count = 0;int n = arr.size();int cur = 0;while(cur < n){if(arr[cur] == 0)count++;cur++;}//开辟新空间arr.reserve(n+count);//此时cur == n,cur--;//重新指向最后一个元素int dest = n+count-1;while(cur >= 0){if(arr[cur]){//不是0,无需复写arr[dest--] = arr[cur--];}else{//复写0arr[dest--] = 0;arr[dest--] = 0;cur--;}}arr.reserve(n);//恢复数组原状}
};

简单分析一下复杂度:只遍历了数组,时间复杂度为O(N);由于使用了reserve开辟了新空间,空间复杂度:O(N)
方法二
能不能在O(1)的空间复杂度下完成该题呢?
我们可以使用两个指针,cur指向最后一个要写的元素,dest指向数组的最后一个位置。
- 若cur为0,复写0,dest移动两次
- 若cur不为0,复写,dest移动一次
那现在的问题就是如何找最后一个要复写的位置。
通过模拟我们可以发现,cur = 0 ,dest = -1;让cur与dest同时走,若cur不为0,则都移动一次;若cur为0,cur移动一次,dest移动两次;直到dest走到数组的末尾,此时cur位置就是最后一个要写的位置

public:void duplicateZeros(vector<int>& arr) {int cur = 0;int dest = -1;int n = arr.size();while(dest < n-1){if(arr[cur] == 0)dest += 2;elsedest++;cur++;}}for( ; cur >=0; cur--){if(arr[cur])arr[dest--] = arr[cur];else{arr[dest--] = 0;arr[dest--] = 0;}}}
};

此时我们发现程序没过,情况又没想全

class Solution {
public:void duplicateZeros(vector<int>& arr) {int cur = 0;int dest = -1;int n = arr.size();while(cur < n){if(arr[cur] == 0)dest += 2;elsedest++;//防止越界if(dest >= n-1)break;cur++;}//已经越界,修正if(dest == n){arr[n-1] = 0;dest-=2;cur--;}//从后向前复写for( ; cur >=0; cur--){if(arr[cur])arr[dest--] = arr[cur];else{arr[dest--] = 0;arr[dest--] = 0;}}}
};

此时,该代码地时间复杂度为O(N);空间复杂度为:O(1)
4.快乐数

leetcode 202.快乐数
根据题意,通过画图我们可以发现,这就是一种循环往复地题目。此时我们就可以考虑双指针算法。

看到这个环形,是不是会想起链表那里有一个判断环形链表的题目,这两题很相似。
我们可以知道,当重复执行x的时候,数据会陷⼊到⼀个「循环」之中。
而「快慢指针」有⼀个特性,就是在⼀个圆圈中,快指针总是会追上慢指针的(证明参考链表部分),也就是说他们总会相遇在⼀个位置上。如果相遇位置的值是1,那么这个数⼀定是快乐数;如果相遇位置不是1的话,那么就不是快乐数。
class Solution {
public:int Sum(int n){int sum = 0;while(n){sum += (n%10)*(n%10);n/=10;}return sum;}bool isHappy(int n) {int slow = n;int fast = Sum(n);//让fast先走一步while(fast != slow){slow = Sum(slow);fast = Sum(Sum(fast));}//当二者相等时,若为1,则是快乐数,否则则不是return slow == 1;}
};
5.盛水最多的容器

leetcode 11.盛水最多的容器
首先我们要明白,这个容器的容量是:两个柱子之间的距离×两柱中较矮的一个
所以此题我们可以利用双指针,寻找两柱中组成的容器中最大的一个即可。
方法一(暴力求解)
枚举出能构成的所有容器,找出其中容积最大的值。
容器容积的计算⽅式:
设两指针分别指向水槽板的最左端以及最右端,此时容器的宽度为j - i
由于容器的⾼度由两板中的短板决定,因此可得容积公式:v = (j - i) * min( height[i], height[j])
class Solution {
public:int maxArea(vector<int>& height) {int v = 0;int n = height.size();for(int i=0; i<n; i++){for(int j = i+1; j<n; j++){v = max(v,((j-i)*min(height[i],height[j])));}}return v;}
};

方法二(左右指针)
观察暴力解法以后,我们可以发现一个规律:
当使用最开始的左右区间算出来一个V1后,我们没必要使用这两个区间中较小的一个去和其它数枚举,因为枚举出来的结果一定是小于V1的。

所以,可以按照以下步骤:
- 先根据当前两柱计算V
- 舍去两柱子中较小的一个
- 根据新的柱子再计算体积tmp,V = max(V,tmp)
class Solution {
public:int maxArea(vector<int>& height) {int v = 0;int left = 0;int right = height.size()-1;while(left < right){//先计算当前两柱组成的大小int tmp = (right-left) * min(height[left],height[right]);v = max(v,tmp);if(height[left] < height[right])left++;elseright--;}return v;}
};
6.有效三角形的个数

leetcode 611.有效三角形的个数
我们都知道,组成三角形的条件是:任意两边之和大于第三边。
方法一(暴力求解)
但是使用这个条件只想到一个暴力解法,虽然说是暴⼒求解,但是还是想优化⼀下
判断三⻆形的优化:
- 如果能构成三⻆形,需要满⾜任意两边之和要大于第三边。但是实际上只需让较小的两条边之和大于第三边即可。
- 因此我们可以先将原数组排序,然后从小到大枚举三元组,一方面省去枚举的数量,另一方面方便判断是否能构成三⻆形。
class Solution {
public:int triangleNumber(vector<int>& nums) {int n = nums.size();sort(nums.begin(),nums.end());int count = 0;for(int i=0; i<n; i++){for(int j=i+1; j<n; j++){for(int k = j+1; k<n; k++){if(nums[i] + nums[j] > nums[k])count++;}}}return count;}
};
方法二(左右指针)
将数组排序以后我们可以发现,如果我们固定最右侧数为第三条边,就只需使用左右指针找另外两条即可。
而且如果最左侧的数和右侧数加起来已经大于第三边了,那么左侧和右侧之间的数一定大于第三边,无需再枚举。

class Solution {
public:int triangleNumber(vector<int>& nums) {//先按照升序排序sort(nums.begin(),nums.end());int max = nums.size() - 1;int ret = 0;//至少要存在3条边while(max >= 2){int left = 0;int right = max - 1;while(left < right){if(nums[left] + nums[right] > nums[max]){ret += right - left;right--;}elseleft++;}max--;}return ret;}
};
7.两数之和

leetcode 179.和为target的两个数
由于该数组是升序的,那么我们可以直接使用双指针,计算左右指针之和
- 若和小于target,左指针右移
- 若和大于target,右指针左移

class Solution {
public:vector<int> twoSum(vector<int>& price, int target) {vector<int> ret;int left = 0;int right = price.size()-1;while(left < right){if(price[left]+price[right] < target)left++;else if(price[left] + price[right] > target)right--;else{break;}}return {price[left],price[right]};}
};
8.三数之和

leetcode 15.三数之和
这一题和上一题两数之和的解法非常类似,唯一的不同点就是:该题不允许有重复的三元组。
- 先排序
- 固定一个数aim
- 使用两数之和法,找和为 - aim 的两个数即可
- 不漏
- 找到一个数以后,left++,right- -继续找
- 去重
- left 与right均需要去重,如果left++后任然和之前的相同,那就继续++;right同理,仍需要 - -
- aim去重,如果aim移动后,仍然和上一个相等,那就继续移动
- 不漏

class Solution {
public:vector<vector<int>> threeSum(vector<int>& nums) {vector<vector<int>> ret;sort(nums.begin(),nums.end());int n = nums.size();int i = 0;while(i < n){if(nums[i] > 0)//若num对应的都已经大于0,那么left 与right就更大,和不可能为0了break;int aim = -nums[i];//固定一个数,取其相反数int left = i+1;int right = n-1;while(left < right){int sum = nums[left] + nums[right];if(sum > aim)right--;else if(sum < aim)left++;else{ret.push_back({nums[i],nums[left],nums[right]});//避免遗漏,继续找left++;right--;//left,right去重while(left < right && nums[left] == nums[left-1])left++;while(left < right && nums[right] == nums[right+1])right--;}}i++;while(i < n && nums[i] == nums[i-1])i++;}return ret;}
};
9.四数之和

leetcode 18.四数之和
该题是在三数之和的基础之上的变形。
仍然还是采用上面的做法,
- 先排序
- 固定一个数a
- 利用三数之和,固定一个数b,找和为target - nums[a] - nums[b]的数
- 不漏
- 找到一个数以后,left++,right- -继续找
- 去重
- left 与right均需要去重,如果left++后任然和之前的相同,那就继续++;right同理,仍需要 - -
- b去重,如果b移动后,仍然和上一个相等,那就继续移动
- a去重,如果a移动后,仍然和上一个相等,那就继续移动
- 不漏
class Solution {
public:vector<vector<int>> fourSum(vector<int>& nums, int target) {sort(nums.begin(),nums.end());vector<vector<int>> ret;int n = nums.size();int a = 0;while(a < n){int b = a+1;while(b < n){long long aim = (long long)target -nums[a] - nums[b];int left = b+1;int right = n-1;while(left < right){if(nums[left] + nums[right] < aim)left++;else if(nums[left] + nums[right] > aim)right--;else{ret.push_back({nums[a],nums[b],nums[left],nums[right]});left++;right--;while(left < right && nums[left] == nums[left-1])left++;while(left< right && nums[right] == nums[right+1])right--;}}b++;while(b < n && nums[b] == nums[b-1])b++;}a++;while(a < n && nums[a] == nums[a-1])a++;}return ret;}
};
相关文章:
【leetcode】双指针算法题
文章目录 1.算法思想2.移动零3.复写零方法一方法二 4.快乐数5.盛水最多的容器方法一(暴力求解)方法二(左右指针) 6.有效三角形的个数方法一(暴力求解)方法二(左右指针) 7.两数之和8.…...
vue-router 源码分析——8.重定向
这是对vue-router 3 版本的源码分析。 本次分析会按以下方法进行: 按官网的使用文档顺序,围绕着某一功能点进行分析。这样不仅能学习优秀的项目源码,更能加深对项目的某个功能是如何实现的理解。这个对自己的技能提升,甚至面试时…...
CAN总线协议
CAN总线协议,全程为控制器局域网(Controller Area Network)协议,是一种用于实时应用的串行通讯协议。该协议由德国某公司专门为汽车行业开发,并逐渐成为一种标准,这是国际上应用最广泛的现场总线之一。 一…...
NLP篇1
场景:假设给你一篇文章。 目标:说白了,就是数学的分类。但是如何实现分类呢。下面将逐步一 一 分析与拆解。先把目标定好了和整体框架定好了。而不是只见树木而不见森林。 情感分类(好评、差评,中性) 整体…...
【一念发动便是行】念头,就是命运
一个个恶念累积就是负能量,念头就是命运,克除恶念,防范念头,念头都有能量,学圣学须内外庄严检肃,言语有灵 多数人的问题都是出在念头上,念头,就是自己的命运; 当我们对自…...
Django + Vue 实现图片上传功能的全流程配置与详细操作指南
文章目录 前言图片上传步骤1. urls 配置2. settings 配置3. models 配置4. 安装Pillow 前言 在现代Web应用中,图片上传是一个常见且重要的功能。Django作为强大的Python Web框架,结合Vue.js这样的现代前端框架,能够高效地实现这一功能。本文将…...
【介绍下R-tree,什么是R-tree?】
🌈个人主页: 程序员不想敲代码啊 🏆CSDN优质创作者,CSDN实力新星,CSDN博客专家 👍点赞⭐评论⭐收藏 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共…...
每天10个js面试题(二)
1.事件轮询? JavaScript 是单线程的,同一时间只能做一件事。所有任务都需要排队,前一个任务结束,才会执行后一个任务,为了保证任务有序的执行,事件轮询就是单线程任务调度的一种方式,单线程任务…...
深入理解【 String类】
目录 1、String类的重要性 2、常用方法 2、1 字符串构造 2、2 String对象的比较 2、3 字符串查找 2、4字符转换 数值和字符串转换: 大小写转化: 字符串转数组: 格式转化: 2、5 字符串替换 2、6字符串拆分 2、7 字符串…...
Nacos 2.x 系列【20】集群部署
文章目录 1. 前言2. 部署服务端2.1 准备工作2.2 集群节点配置2.3 鉴权配置2.4 配置数据源2.5 配置 IP2.6 配置端口2.7 启动集群 3. 部署模式3.1 直连模式3.2 地址服务器模式3.2.1 地址服务器3.2.2 配置 3.3 VIP 模式(推荐)3.3.1 Nginx3.3.1 域名 1. 前言…...
LeetCode刷题记录:(15)三角形最小路径和
知识点:倒叙的动态规划 题目传送 解法一:二维动态规划【容易理解】 class Solution {public int minimumTotal(List<List<Integer>> triangle) {int n triangle.size();if (n 1) {return triangle.get(0).get(0);}// dp[i][j]:走到第i层第…...
【大数据面试题】35 Spark 怎么做优化?
一步一个脚印,一天一道大数据面试题 博主希望能够得到大家的点赞收,藏支持!非常感谢~ 点赞,收藏是情分,不点是本分。祝你身体健康,事事顺心! Spark 如何做优化一直是面试过程中常问的问题。那么这次也仅以此篇文章总结梳理,希望对大家有帮助。 通用优化 Spark 一般遇…...
2024年保安员职业资格考试题库大数据揭秘,冲刺高分!
186.安全技术防范是一种由探测、()、快速反应相结合的安全防范体系。 A.保安 B.出警 C.延迟 D.监控 答案:C 187.安全技术防范是以()和预防犯罪为目的的一项社会公共安全业务。 A.预防灾害 B.预防损失 C.预防失…...
怎么搭建个人博客教程,附云主机选购指南
一、搭建个人博客教程 1. 规划博客内容与技术栈 确定博客主题:首先明确博客的定位和主题,这将影响后续的技术选择和内容规划。选择技术栈:根据个人偏好和技术背景,选择合适的建站技术。例如,可以使用WordPress&#…...
使用Llama3/Qwen2等开源大模型,部署团队私有化Code Copilot和使用教程
目前市面上有不少基于大模型的 Code Copilot 产品,部分产品对于个人开发者来说可免费使用,比如阿里的通义灵码、百度的文心快码等。这些免费的产品均通过 API 的方式提供服务,因此调用时均必须联网、同时需要把代码、提示词等内容作为 API 的…...
C语言_结构体初阶(还未写完)
结构体的声明 1. 什么是结构?结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量 数组:一组相同类型元素的集合 结构体:一组不一定相同类型元素的集 2. 结构的声明 struct tag //tag根据实际情况给名字…...
MyBatis-Plus:快速入门
1. 概念 MyBatis-Plus(简称 MP)是一个MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。其突出的特性如下: * **无侵入**:只做增强不做改变,引入它不会对现有…...
【高级篇】第9章 Elasticsearch 监控与故障排查
9.1 引言 在现代数据驱动的应用架构中,Elasticsearch不仅是海量数据索引和搜索的核心,其稳定性和性能直接影响到整个业务链路的健康度。因此,建立有效的监控体系和掌握故障排查技能是每一位Elasticsearch高级专家的必备能力。 9.2 监控工具:洞察与优化的利器 在Elastics…...
【前端】上传和下载zip文件,有进度条(el-progess)
文章目录 上传下载进度条 场景:要上传一个zip,调用接口,然后下载一个zip。调用接口的接口响应要显示在进度条中。 上传 上传用的是input原生控件,在页面中隐藏。accept"application/zip"限制只能上传zip。 点击button…...
2024年软件测试面试题,精选100+,附答案+文档
🍅 视频学习:文末有免费的配套视频可观看 🍅 点击文末小卡片 ,免费获取软件测试全套资料,资料在手,涨薪更快 Part1 1、你的测试职业发展是什么? 测试经验越多,测试能力越高。所以我…...
Hermes Agent 总记不住你说的话?3 步治好 AI 助手的“健忘症“
你有没有这样的经历:你跟它说"每次写营销文章,记得先加载技能审核",它答应得好好的。结果下一篇写出来,你又得说一遍同样的话。它就像一个只点头不记事的实习生——每轮对话都重头来过。又或者,昨天刚刚聊完…...
虚幻引擎Pak文件可视化分析工具原理与实践
1. 为什么一个Pak文件查看器值得花两周重写三遍?虚幻引擎项目打包后生成的.pak文件,对绝大多数开发者来说就是个“黑盒”——你清楚它装着所有资源:贴图、音频、蓝图、关卡数据,甚至UAsset序列化后的二进制结构;但你完…...
08-系统技术架构师必备——分布式系统理论与数据一致性
关键词:分布式系统、CAP定理、BASE理论、Paxos、Raft、分布式事务、TCC、Saga、一致性算法 分布式系统 CAP定理 分布式事务 一致性算法 Paxos Raft TCC Saga 系统技术架构师必备——分布式系统理论与数据一致性 摘要 分布式系统是系统技术架构师必须跨越的"分水岭"…...
【咨询业AI Agent应用成熟度评估模型】:基于217家机构实测数据的4级能力图谱与升级路线图
更多请点击: https://codechina.net 第一章:【咨询业AI Agent应用成熟度评估模型】:基于217家机构实测数据的4级能力图谱与升级路线图 本模型基于对全球217家管理咨询、战略咨询与数字化转型服务商的实地调研与系统性能力测评,覆…...
告别黑屏!手把手教你用QNX Screen API在8295座舱屏上显示第一个窗口
从零到一:QNX Screen图形开发实战指南 1. 初识QNX Screen图形系统 在车载信息娱乐系统和数字座舱开发领域,QNX Screen图形系统扮演着至关重要的角色。作为黑莓QNX实时操作系统中的核心图形框架,它提供了高性能、低延迟的图形显示能力…...
centos7启动yum 安装失败原因(个人观点如有错误请指正)
第一步:修复 DNS(最关键) bash 运行 echo "nameserver 8.8.8.8" >> /etc/resolv.conf echo "nameserver 114.114.114.114" >> /etc/resolv.conf第二步:下载阿里云 CentOS7 国内源 bash 运行 curl…...
FactoryBluePrints终极指南:戴森球计划蓝图库助你轻松建造完美工厂
FactoryBluePrints终极指南:戴森球计划蓝图库助你轻松建造完美工厂 【免费下载链接】FactoryBluePrints 游戏戴森球计划的**工厂**蓝图仓库 项目地址: https://gitcode.com/GitHub_Trending/fa/FactoryBluePrints 你是否曾在戴森球计划中为复杂的工厂布局而头…...
n8n CVE-2025-68668沙箱逃逸漏洞深度解析与24小时应急指南
1. 这不是普通补丁——CVE-2025-68668 是 n8n 工作流引擎的“心脏停搏”级漏洞你刚收到企业安全团队的紧急邮件,标题加了三个感叹号:“n8n 集群所有节点需立即下线评估!”——而你负责维护的 37 个核心自动化流程,正支撑着订单履约…...
3个问题让你了解为什么我们需要中文AI的“数据粮仓“
3个问题让你了解为什么我们需要中文AI的"数据粮仓" 【免费下载链接】MNBVC MNBVC(Massive Never-ending BT Vast Chinese corpus)超大规模中文语料集。对标chatGPT训练的40T数据。MNBVC数据集不但包括主流文化,也包括各个小众文化甚至火星文的数据。MNBVC…...
5个步骤在Windows Hyper-V上完美运行macOS虚拟机
5个步骤在Windows Hyper-V上完美运行macOS虚拟机 【免费下载链接】OSX-Hyper-V OpenCore configuration for running macOS on Windows Hyper-V. 项目地址: https://gitcode.com/gh_mirrors/os/OSX-Hyper-V 你是否想在Windows电脑上体验macOS的流畅操作?OSX-…...
