双指针算法详解
目录
一、双指针
二、双指针题目
1.移动零
解法:
代码:
2.复写零
编辑
解法:
代码:
边界情况处理:
3.快乐数
编辑
解法:快慢指针
代码:
4.盛水最多的容器
解法:(对撞指针)
代码:
5.有效三角形的个数
编辑
解法:
代码:
6.和为s的两个数字
解法:(对撞指针)
代码:
7.三数之和
解法:
代码:
一、双指针
对撞指针:⼀般⽤于顺序结构中,也称左右指针。
- 对撞指针从两端向中间移动。⼀个指针从最左端开始,另⼀个从最右端开始,然后逐渐往中间逼近。
- 对撞指针的终⽌条件⼀般是两个指针相遇或者错开(也可能在循环内部找到结果直接跳出循环),也就是:
- left == right (两个指针指向同⼀个位置)
- left > right (两个指针错开)
快慢指针:⼜称为⻳兔赛跑算法,其基本思想就是使⽤两个移动速度不同的指针在数组或链表等序列结构上移动。这种⽅法对于处理环形链表或数组⾮常有⽤。
- 在⼀次循环中,每次让慢的指针向后移动⼀位,⽽快的指针往后移动两位,实现⼀快⼀慢。
二、双指针题目
1.移动零
283. 移动零 - 力扣(LeetCode)

解法:
两个指针:
- cur:从左到右扫描整个数组
- dest:已处理的数组中,非零元素的最后位置
代码:
class Solution {
public:void moveZeroes(vector<int>& nums) {//双指针for(int cur=0,dest=-1;cur<nums.size();cur++)if(nums[cur])//非零元素swap(nums[++dest],nums[cur]);//交换,dest++}
};
swap(nums[++dest], nums[cur]):这里的操作有两部分:
++dest:先将dest指针向前移动一位。这个步骤确保了每当找到一个非零元素时,它会被放置到数组的前面,而dest会保持在下一个非零元素的位置。swap(nums[dest], nums[cur]):将cur指向的非零元素与dest指向的元素交换位置。此时,cur指向的非零元素被放到数组的前面,dest也向前移动一位,以准备接收下一个非零元素。
2.复写零
1089. 复写零 - 力扣(LeetCode)
解法:
从后往前复写,大体流程分为两步:
- 先找到最后一个复写的数
先判断cur位置的值
决定dest向后移动一步或者两步
判断一下dest是否已经到结束为止
cur++- 从后往前进行复写操作
代码:
class Solution {
public:void duplicateZeros(vector<int>& arr) {//1.先找到最后一个数int cur=0,dest=-1,n=arr.size();while(cur<n){if(arr[cur]) dest++;//不等于0,走1步else dest+=2;//等于0,走两步if(dest >= n-1) break;cur++;}//2.处理一下边界情况(最后一个元素是0,需要复写两遍,会导致越界;)if(dest == n)//判断越界{arr[n - 1]=0;cur--;dest-=2;}//3.从后向前完成复写操作while(cur >= 0){if(arr[cur]) arr[dest--]=arr[cur--];else{arr[dest--]=0;arr[dest--]=0;cur--;}}}
};
边界情况处理:
如果越界:1.n-1位置的值修改成0;
2.cur向前移动一步
3.dest向前移动两步
3.快乐数
202. 快乐数 - 力扣(LeetCode)
解法:快慢指针
【快慢指针】有⼀个特性,就是在⼀个圆圈中,快指针总是会追上慢指针的,也就是说他们总会相遇在⼀个位置上。如果相遇位置的值是 1 ,那么这个数⼀定是快乐数;如果相遇位置不是 1的话,那么就不是快乐
- 定义快慢指针
- 满指针每次向后移动一步,块指针每次向后移动两步
- 判断相遇时候的值即可
补充:求一个数n每个位置上的数组的平方和
1.把数 n 每⼀位的数提取出来:循环迭代下⾯步骤:
- int t = n % 10 提取个位;
- n /= 10 ⼲掉个位;
直到 n 的值变为 0 ;2.提 取每⼀位的时候,⽤⼀个变量 tmp 记录这⼀位的平⽅与之前提取位数的平⽅和
- tmp = tmp + t * t
代码:
class Solution {
public:int Sum(int n){int sum=0;while(n){int t=n%10;sum+=t*t;n/=10;}return sum;}bool isHappy(int n) {//双指针,solw走一步,fast走两步int slow=n,fast=Sum(n);while(slow!=fast){slow=Sum(slow);fast=Sum(Sum(fast));}return slow==1;}
};
4.盛水最多的容器
11. 盛最多水的容器 - 力扣(LeetCode)

解法:(对撞指针)
设两个指针 left , right 分别指向容器的左右两个端点,此时容器的容积 :v = (right - left) * min( height[right], height[left])容器的左边界为 height[left] ,右边界为 height[right] 。为了⽅便叙述,我们假设「左边边界」⼩于「右边边界」。如果此时我们固定⼀个边界,改变另⼀个边界,⽔的容积会有如下变化形式:
- 容器的宽度⼀定变⼩。
- 由于左边界较⼩,决定了⽔的⾼度。如果改变左边界,新的⽔⾯⾼度不确定,但是⼀定不会超 过右边的柱⼦⾼度,因此容器的容积可能会增⼤。
- 如果改变右边界,⽆论右边界移动到哪⾥,新的⽔⾯的⾼度⼀定不会超过左边界,也就是不会 超过现在的⽔⾯⾼度,但是由于容器的宽度减⼩,因此容器的容积⼀定会变⼩的。
由此可⻅,左边界和其余边界的组合情况都可以舍去。所以我们可以 left++ 跳过这个边界,继续去判断下⼀个左右边界。当我们不断重复上述过程,每次都可以舍去⼤量不必要的枚举过程,直到 left 与 right 相遇。期间产⽣的所有的容积⾥⾯的最⼤值,就是最终答案
代码:
class Solution
{
public:int maxArea(vector<int>& height) {int left = 0, right = height.size() - 1, ret = 0;while(left < right){int v = min(height[left], height[right]) * (right - left);ret = max(ret, v);// 移动指针if(height[left] < height[right]) left++;else right--;}return ret;}
};
5.有效三角形的个数
611. 有效三角形的个数 - 力扣(LeetCode)
解法:
先将数组排序
双指针法:
从
i = n-1开始,遍历每个可能的第三条边(从最大的边开始)。然后使用两个指针left和right,分别指向数组的起始和i-1位置。
- 如果
nums[left] + nums[right] > nums[i],说明当前的left和right可以和nums[i]组成一个三角形,并且[left, right-1]之间的所有组合也满足条件。此时,结果增加right - left。- 如果不满足条件,说明
nums[left]太小,无法与nums[right]和nums[i]组成三角形,需要增大left。
代码:
class Solution {
public:int triangleNumber(vector<int>& nums) {sort(nums.begin(),nums.end());int n=nums.size(),ret=0;for(int i=n-1;i>=2;i--){int left=0,right=i-1;while(left<right){if(nums[left]+nums[right]>nums[i]){ret+=right-left;//如果nums[left]+nums[right]>nums[i]说明[left,right-1]区间上的//所有元素均可以与nums[right]构成比nums[i]大的二元组//有right-left种right--;}else//nums[left] + nums[right] <= nums[i]说明left位置的元素是不可能与[left+1,right]位置上的元素构成满足条件的二元组{left++;}}}return ret;}
};
6.和为s的两个数字

解法:(对撞指针)
-
初始化左右指针:
left = 0和right = price.size() - 1。left指向数组的起始位置,right指向数组的末尾位置。 -
循环条件:
while (left < right)。这表示只要left小于right,就继续进行搜索。如果left>=right,说明已经遍历完了所有可能的组合。 -
计算当前和:
int sum = price[left] + price[right]。计算当前指针所指向的两个元素的和。 -
判断和的关系:
- 如果和大于目标值:
sum > target,说明当前两个数的和太大了,可以将right指针左移,减小和。 - 如果和小于目标值:
sum < target,说明当前两个数的和太小了,可以将left指针右移,增大和。 - 如果和等于目标值:
sum == target,找到目标和,直接返回这两个元素。
- 如果和大于目标值:
代码:
class Solution {
public:vector<int> twoSum(vector<int>& price, int target) {int left=0,right=price.size()-1;while(left<right){int sum=price[left]+price[right];if(sum>target) right--;//当 nums[left] + nums[right] > target 时,nums[right]与最小的数相加还大于target,剩下的也肯定大于,直接right--else if(sum<target) left++;//同理,当 nums[left] + nums[right] > target 时,直接left++else return {price[left],price[right]};}return {-1,-1};}
};
7.三数之和
15. 三数之和 - 力扣(LeetCode)

解法:
利⽤在两数之和那⾥⽤的双指针思想:
- 先排序;
- 然后固定⼀个数 a :
- 在这个数后⾯的区间内,使⽤「双指针算法」快速找到两个数之和等于 -a 即可。
但是要注意的是,这道题⾥⾯需要有「去重」操作1.找到⼀个结果之后, left 和 right 指针要「跳过重复」的元素;2.当使⽤完⼀次双指针算法之后,固定的 a 也要「跳过重复」的元素
代码:
class Solution {
public:vector<vector<int>> threeSum(vector<int>& nums) {vector<vector<int>> ret;//1.排序sort(nums.begin(),nums.end());//2.利用双指针解决问题int n=nums.size();for(int i=0;i<n;){if(nums[i]>0) break;int left=i+1,right=n-1,target=-nums[i];while(left<right){int sum=nums[left]+nums[right];if(sum>target)right--;else if(sum<target)left++;else{ret.push_back({nums[i],nums[left],nums[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;}
};
感谢,再见
相关文章:
双指针算法详解
目录 一、双指针 二、双指针题目 1.移动零 解法: 代码: 2.复写零 编辑 解法: 代码: 边界情况处理: 3.快乐数 编辑 解法:快慢指针 代码: 4.盛水最多的容器 解法:(对撞指针)…...
MySQL的最左匹配原则是什么
最左匹配原则是应用于联合索引的规则。 对于以下表F:f1,f2,f3;建立了联合索引(f2,f3),那么我们在查询的时候如果是: select * from F where f2 ? and f3 ?; 或 sele…...
LeetCode:106.从中序与后序遍历序列构造二叉树
跟着carl学算法,本系列博客仅做个人记录,建议大家都去看carl本人的博客,写的真的很好的! 代码随想录 LeetCode:106.从中序与后序遍历序列构造二叉树 给定两个整数数组 inorder 和 postorder ,其中 inorder …...
22. 【.NET 8 实战--孢子记账--从单体到微服务】--记账模块--切换主币种
这篇文章我们将结合主币种设置以及收支记录实现切换主币种后重新计算以前记录的转换后的金额。那么,为什么要在切换主币种后要重新计算转换后的金额呢?有以下两个原因: 统一的币种,方便我们统计数据方便用户按照当地的币种查看收…...
01.02周四F34-Day43打卡
文章目录 1. 地是湿的。昨晚估计下雨了。2. 你可能把包丢在餐厅里了吧?3. 她说他可能误了航班。4. 我本来应该早点来的,但路上特别堵。5. 约翰可能在那次事故中受了重伤。6. 这是一个情景对话7. 我本可以走另一条路的。8. 我准是瘦了不少,你看我这裤子现在多肥。9. 钱没了!会…...
行业商机信息付费小程序系统开发方案
行业商机信息付费小程序系统,主要是整合优质行业资源,实时更新的商机信息。在当今信息爆炸的时代,精准、高效地获取行业商机信息对于企业和个人创业者而言至关重要。 一、使用场景 日常浏览:用户在工作间隙或闲暇时间,…...
cut-命令详解
一、命令 1.cut列截取命令 cut命令的默认分隔符是制表符 2.参数: -f 列号 #提取第几列-d 分隔符 #按照指定分隔符分割列-c 字符范围 #不依赖分隔符来区分列,而是通过字符范围(行首为0)来进行字段提取。“n-”表…...
Apache MINA 反序列化漏洞CVE-2024-52046
漏洞描述: Apache MINA 是一个功能强大、灵活且高性能的网络应用框架。它通过抽象网络层的复杂性,提供了事件驱动架构和灵活的 Filter 链机制,使得开发者可以更容易地开发各种类型的网络应用。 Apache MINA 框架的 ObjectSerializationDeco…...
二、AI知识(神经网络)
二、AI知识(神经网络) 1.常用算法 FNN CNN RNN LSTM DNN GRU 2.深度学习中概念及算法 1. 感知机 感知机(Perceptron)是一种最早的人工神经网络模型之一,通常用来解决二分类问题。它由弗兰克罗森布拉特&#…...
node.js之---子线程(child_process)模块
为什么需要子线程(child_process)模块 Worker Threads 的基本概念 如何使用 Worker Threads Worker Threads 的性能 Worker 线程的优势和限制 进阶用法:共享内存 为什么需要子线程(child_process)模块 在 Node.js…...
Json字符串解析失败
通过第三方服务,拿到响应体的data对象(拿到的时候对象是有值的) 通过JSON.parseObject方法,拿到的对象,值为null 通过查看对应的json字符串,发现命名不一样... JSONField SeriealizedName注解是用来解析j…...
LeetCode算法题——螺旋矩阵ll
题目描述 给你一个正整数n,生成一个包含1到n2所有元素,且元素按顺时针顺序螺旋排列的n x n正方形矩阵matrix 。 示例 输入:n 3 输出:[[1,2,3],[8,9,4],[7,6,5]]题解 思路: 将整个过程分解为逐圈填充的过程…...
【开源社区openEuler实践】hpcrunner
title: 探索 Hpcrunner:高性能计算的得力助手 date: ‘2024-12-31’ category: blog tags: Hpcrunner高性能计算任务调度资源优化 sig: HPC archives: ‘2024-12’ author:way_back summary: Hpcrunner 作为高性能计算领域的一款实用工具,专注于优化任务…...
linux下安装达梦数据库v8详解
目录 操作系统、数据库 1、下载达梦数据库 2、安装前准备 2.1、建立数据库用户和组 2.2、修改文件打开最大数 2.3、挂载镜像 2.4、新建安装目录 3、数据库安装 4、配置环境变量 5、初始化数据库实例 6、注册服务 7、使用数据库 8、卸载数据库 9、多实例管理 10、…...
Redis的常用命令
Redis中文字典网站 redis 命令手册https://redis.com.cn/commands.html Keys * 查看当前库所有的key exists ke 判断某个key是否存在 type key查看你的key是什么类型 Del key删除执行的key数据 unlink key非阻塞删除,仅仅将keys从keyspace元数据中删除…...
Docker入门常用命令总结
1.从远程仓库拉取一个纯净的镜像 docker pull docker .io/centos 2.创建并进入容器(左外右内) docker run --name xxx -dit 镜像id(镜像名称:Tag) /bin/bash 【参数必须放在镜像ID之前】 -i 让Docker分配一个伪终端,并…...
【Qt】容器控件、布局管理控件
目录 容器控件 QGroupBox QTabWidget 布局管理控件 QVBoxLayout 例子: QHBoxLayout 例子: QGridLayout 例子: 例子: QFormLayout 例子: QSpacerItem 例子: 容器控件 QGroupBox 表示一个带有…...
cesium小知识:常见的20多种property详解
要详细解释 Cesium 中所有的 Property 类,内容确实会非常丰富且详尽。 Property 基础 Property 是 Cesium 中用于表示随时间或条件变化的值的基础类。它允许你定义属性值如何根据时间、用户交互或其他逻辑动态改变。Property 的设计使得你可以创建复杂的动画和交互效果,而…...
图数据库 | 17、高可用分布式设计(上)
我们在前面的文章中,探索了多种可能的系统扩展方式,以及每种扩展方式的优劣。 本篇文章将通过具体的架构设计方案来对每一种方案的设计、投入产出比、各项指标与功能,以及孰优孰劣等进行评价。 在设计高性能、高可用图数据库的时候…...
1.运控概述
以下并不是我原创(包括图片),都是来源于网络收集。如CSDN博主,朝夕教育,AI等。 什么是运动控制 运控是指“控制移动”之意,可以利用各种电机进行位置控制等操作,让机器听懂你的指令。 什么是…...
Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
C++ 基础特性深度解析
目录 引言 一、命名空间(namespace) C 中的命名空间 与 C 语言的对比 二、缺省参数 C 中的缺省参数 与 C 语言的对比 三、引用(reference) C 中的引用 与 C 语言的对比 四、inline(内联函数…...
如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...
基于SpringBoot在线拍卖系统的设计和实现
摘 要 随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统,主要的模块包括管理员;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...
基于PHP的连锁酒店管理系统
有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发,数据库mysql,前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...
云安全与网络安全:核心区别与协同作用解析
在数字化转型的浪潮中,云安全与网络安全作为信息安全的两大支柱,常被混淆但本质不同。本文将从概念、责任分工、技术手段、威胁类型等维度深入解析两者的差异,并探讨它们的协同作用。 一、核心区别 定义与范围 网络安全:聚焦于保…...
java高级——高阶函数、如何定义一个函数式接口类似stream流的filter
java高级——高阶函数、stream流 前情提要文章介绍一、函数伊始1.1 合格的函数1.2 有形的函数2. 函数对象2.1 函数对象——行为参数化2.2 函数对象——延迟执行 二、 函数编程语法1. 函数对象表现形式1.1 Lambda表达式1.2 方法引用(Math::max) 2 函数接口…...
Win系统权限提升篇UAC绕过DLL劫持未引号路径可控服务全检项目
应用场景: 1、常规某个机器被钓鱼后门攻击后,我们需要做更高权限操作或权限维持等。 2、内网域中某个机器被钓鱼后门攻击后,我们需要对后续内网域做安全测试。 #Win10&11-BypassUAC自动提权-MSF&UACME 为了远程执行目标的exe或者b…...


