学习算法之双指针篇(1)(c++版)
一、概念和分类双指针是一种‌用两个指针协同移动来减少遍历次数、降低时间复杂度的思路。常见的有对撞指针和快慢指针。1.对撞指针•对撞指针是从两端向中间移动。⼀个指针从最左端开始另⼀个从最右端开始然后逐渐往中间逼近。终⽌条件⼀般是两个指针相遇或者错开也可能在循环内部找到结果直接跳出循环。2.快慢指针•快慢指针的基本思想是使⽤两个移动速度不同的指针在数组或链表等序列结构上移动。这种⽅法对于处理环形链表或数组⾮常有用。通常是慢指针走一步快指针走两步实现一快一慢。二、题目1、移动零 283. 移动零 - 力扣LeetCodehttps://leetcode.cn/problems/move-zeroes/description/1. 题目描述给定一个数组nums编写一个函数将所有0移动到数组的末尾同时保持非零元素的相对顺序。请注意必须在不复制数组的情况下原地对数组进行操作。示例 1:输入:nums [0,1,0,3,12]输出:[1,3,12,0,0]示例 2:输入:nums [0]输出:[0]提示:1 nums.length 104-231 nums[i] 231 - 12.思路这个题是要求我们把数组分为两块区间把零都移到后半块区间去。所以我们可以使用两个“指针”⽤⼀个 cur指针来扫描整个数组另⼀个dest指针⽤来记录⾮零数序列的最后⼀个位置。根据 cur在扫描的过程中遇到的不同情况分类处理实现数组的划分。 在遍历期间使[0, dest]的元素全部都是⾮零元素[dest 1, cur - 1]的 元素全是零。注意这里的指针并不真的是两个指针而是模仿指针的行为3.代码实现1.初始化 cur 0⽤来遍历数组dest -1指向⾮零元素序列的最后⼀个位置。 因为刚开始我们不知道最后⼀个⾮零元素在什么位置因此初始化为 -1。2. cur循环遍历每个元素会遇到两种情况。cur遇到0的时候直接cur就好dest不做改变因为要确保[dest1, cur-1]之间的元素都是0如果cur遇到非0元素让dest之后再去和cur的元素交换。这样下来就可以把数组划分完成了。以下是c代码可直接AC。class Solution { public: void moveZeroes(vectorint nums) { for(int cur 0, dest -1; cur nums.size(); cur) { if(nums[cur])//处理非0元素 { swap(nums[cur], nums[dest]); } } } };2.复写零1089. 复写零 - 力扣LeetCodehttps://leetcode.cn/problems/duplicate-zeros/description/1.题目描述给你一个长度固定的整数数组arr请你将该数组中出现的每个零都复写一遍并将其余的元素向右平移。注意请不要在超过该数组长度的位置写入元素。请对输入的数组就地进行上述修改不要从函数返回任何东西。示例 1输入arr [1,0,2,3,0,4,5,0]输出[1,0,0,2,3,0,0,4]解释调用函数后输入的数组将被修改为[1,0,0,2,3,0,0,4]示例 2输入arr [1,2,3]输出[1,2,3]解释调用函数后输入的数组将被修改为[1,2,3]提示1 arr.length 1040 arr[i] 92.思路根据题意如果我们从前向后复写的话会导致后面的数据被掩盖掉所以这个题我们的思路是从后往前复写。因为我们是从后往前复写所以我们要找到最后一个复写的元素这个时候就要用到我们的双指针了。如果可以开辟一个和原数组一样大小的新数组的话我们的可以定义两个指针cur 和 destcur指向当前数组dest指向复写的数组。这是我们会发现当cur指向0时dest要复写两次cur不指向0时dest只需复写一次当dest达到数组的结尾时cur会指向最后一个复写的元素。所以我们根据这个思路我们可以两个指针定义到原数组上进行同样的操作就可以找到最后一个复写的元素了。然后在执行从后往前的复写操作。3.代码实现定义两个指针cur 和 destcur 0 dest -1dest要指向最后一个复写的元素开始时是-1值得注意的是有一个情况要处理例如在这组数据下[1,0,2,3,0,4]dest n所以我们要处理一下边界问题。以下是c代码可直接AC。class Solution { public: void duplicateZeros(vectorint arr) { int cur 0, dest -1; int n arr.size(); // 1.先找到最后一个数 while(cur n) { if(arr[cur] ! 0) dest; else dest 2; if(dest n-1) break;//dest走到结尾了cur已经指向最后一个元素了 cur; } // 2.处理边界情况 if(dest n) { arr[n-1] 0; dest - 2; cur--; } // 3.完成复写 while(cur 0) { if(arr[cur] ! 0) { arr[dest--] arr[cur--]; } else{ arr[dest--] 0; arr[dest--] 0; cur--; } } } };3.快乐数202. 快乐数 - 力扣LeetCodehttps://leetcode.cn/problems/happy-number/description/1.题目描述编写一个算法来判断一个数n是不是快乐数。「快乐数」定义为对于一个正整数每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个数变为 1也可能是无限循环但始终变不到 1。如果这个过程结果为1那么这个数就是快乐数。如果n是快乐数就返回true不是则返回false。示例 1输入n 19输出true解释12 92 82 82 22 68 62 82 100 12 02 02 1示例 2 输入n 2输出false2.思路根据题意我们把 “对于⼀个正整数每⼀次将该数替换为它每个位置上的数字的平⽅和” 记为操作x。当我们对这个数不断执行x时这个过程一定会进入死循环。要么是变换到1之后一直循环1这个数字那么这个数就是题目要求的快乐数要么一直在曾经变换过的数据中循环一直变不到1。那么一定为什么会进入死循环呢这就要用到鸽巢原理了。因为int的最大值为 2^31-1 2147483647我们选一个更大的数 9999999999那么它的变换为 9^2 * 10 810所以变化的区间一定在[1,810]这个区间内。当经历811次变换时一定会进入循环所以根据上述思路我们可以使用快慢指针在循环中快指针一定会追上慢指针的特点来解决问题。我们只需要判断相遇位置的值是否为1即可。3.代码实现class Solution { public: // 操作x int tmp(int n) { int a 0; while(n){ int t n % 10; a t * t; n / 10; } return a; } bool isHappy(int n) { int slow n, fast tmp(n); while(slow ! fast){ // 走一步 slow tmp(slow); // 走两步 fast tmp(tmp(fast)); } return slow 1; } };4.盛最多水的容器 11. 盛最多水的容器 - 力扣LeetCodehttps://leetcode.cn/problems/container-with-most-water/description/1. 题目描述:给定一个长度为n的整数数组height。有n条垂线第i条线的两个端点是(i, 0)和(i, height[i])。找出其中的两条线使得它们与x轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。说明你不能倾斜容器。示例 1输入[1,8,6,2,5,4,8,3,7]输出49解释图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下容器能够容纳水表示为蓝色部分的最大值为 49。示例 2输入height [1,1]输出12.思路方法一可以直接暴力枚举但会超时所以这里不做详细介绍方法二对撞指针设两个指针left right 分别指向容器的左右两个端点所以容器的容积 v (right - left) * min( height[right], height[left])根据这个式子我们假设左边界小于右边界如果此时我们固定⼀个边界改变另⼀个边界水的容积会有如下变化形式1.容器的宽度⼀定变小。2.由于左边界较小决定了水的高度。如果改变左边界新的水面高度不确定但是⼀定不会超过右边的柱子高度因此容器的容积可能会增⼤。3。如果改变右边界⽆论右边界移动到哪⾥新的水面的高度⼀定不会超过左边界也就是不会超过现在的水面高度但是由于容器的宽度减小因此容器的容积⼀定会变小的。所以左边界和其余边界的组合情况都可以舍去。所以我们可以 left跳过这个边界继续去判断下⼀个左右边界。不断重复上述过程直到 left 和 right 相遇。期间产生的最大值就是最终答案。3.代码实现class Solution { public: int maxArea(vectorint height) { int left 0, right height.size()-1; int maxnum 0; while(left right) { int tmp (right - left) * min(height[left], height[right]); maxnum max(tmp, maxnum); if(height[right] height[left]){ right--; } else{ left; } } return maxnum; } };5.有效三角形的个数611. 有效三角形的个数 - 力扣LeetCodehttps://leetcode.cn/problems/valid-triangle-number/description/1.题目描述给定一个包含非负整数的数组nums返回其中可以组成三角形三条边的三元组个数。示例 1:输入:nums [2,2,3,4]输出:3解释:有效的组合是: 2,3,4 (使用第一个 2) 2,3,4 (使用第二个 2) 2,2,3示例 2:输入:nums [4,2,3,4]输出:42.思路在判断3条边是否可以组成三角形的条件是任意两条边之和大于第三条边。那如果这三条边是有序的那么只用判断小的两条边之和大于第三条边即可。方法一暴力三重循环不做详解方法二排序 双指针根据上述分析我们上来就可以对整个数组排序然后固定一个边界 flag利用对撞指针left 和 right 来寻找 [letf , right]在flag的左边也就是比flag小的区间 这个区间满足nums[left] nums[right] nums[flag]的二元组如果这个区间[letf , right]有满足条件的说明区间[letf , right-1]上的所有的元素和nums[right] 组成的二元组都满足条件一共有right - left种此时 right 位置的元素的所有情况相当于全部考虑完毕right--进⼊下⼀轮判断。如果nums[left] nums[right] nums[flag]直接让left即可3.代码实现class Solution { public: int triangleNumber(vectorint nums) { int ret 0; // 先优化将数组排序 sort(nums.begin(),nums.end()); // 利用双指针解决问题先固定最大的数 int flag nums.size()-1; while(flag 2){ int left 0, right flag - 1; while(left right){ if(nums[left] nums[right] nums[flag]){ ret right - left; right--; } else{ left; } } flag--; } return ret; } };

相关新闻

【高质量毕设开题】 基于微信小程序的智慧校园生活服务平台设计与实现(源码+报告)

【高质量毕设开题】 基于微信小程序的智慧校园生活服务平台设计与实现(源码+报告)

温馨提示: 本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示: 本人主页置顶文章(点我)开头有 CSDN平台官方提供的学长联系方式的名片! 温馨提示: 本人主页置顶文章(点我)开头有 CSDN 平…

2026/10/17 10:46:08 阅读更多 →
C#语音测试例程:用System.Speech打造TTS合成验证工具

C#语音测试例程:用System.Speech打造TTS合成验证工具

简介:面向初学者的C#语音合成测试例程,基于Visual Studio 2010与Windows自带System.Speech组件,演示通过Text-to-Speech技术将文本转换为语音播报的全过程,适合刚接触TTS开发、想了解人机交互或无障碍应用实现的开发者&#xff0c…

2026/10/17 10:46:08 阅读更多 →
坐标转换实战:从坐标系原理到代码实现与避坑指南

坐标转换实战:从坐标系原理到代码实现与避坑指南

1. 坐标转换到底在转什么:从一次地图偏移说起坐标转换这个词,听起来像是测绘专业才需要关心的东西,但实际上只要你碰过地图开发、做过定位功能、处理过轨迹数据,甚至只是想把手机拍的照片标到地图上,就一定会跟它打交道…

2026/10/17 10:46:08 阅读更多 →

最新新闻

Argon架构解析:面向毫秒级SLA的AI服务三层解耦设计

Argon架构解析:面向毫秒级SLA的AI服务三层解耦设计

1. 项目概述:这不是一次简单的模型调用,而是一次系统级工程重构“Google 用 Gemini 4 Argon 构建案例”——这个标题乍看像一则新闻简报,但作为在AI基础设施一线摸爬滚打十多年的从业者,我第一反应是:这根本不是在讲“…

2026/10/17 11:32:28 阅读更多 →
n8n集成Gemini 4 Argon与MCP协议构建真Agent工作流

n8n集成Gemini 4 Argon与MCP协议构建真Agent工作流

1. 这不是“又一个AI工作流”,而是n8n生态里首次真正打通MCP协议的Gemini原生集成 我第一次在某跨平台自动化实验室看到这个标题时,下意识点开想确认是不是标题党——毕竟过去两年里,“用XX模型接入n8n”这类文章我至少扫过四十多篇&#xff…

2026/10/17 11:32:28 阅读更多 →
意图优先的版本控制系统:重构代码协作的认知范式

意图优先的版本控制系统:重构代码协作的认知范式

1. 项目概述:这不是又一个Git客户端,而是一次底层协作范式的重写“7个人、5个月,Anthropic造出了Git替代品”——这个标题在技术圈刷屏时,我正带着团队在做一个跨时区协同的嵌入式固件项目。每天早上打开终端,git pull…

2026/10/17 11:32:28 阅读更多 →
DVWA中CSP绕过原理与四类实战利用手法详解

DVWA中CSP绕过原理与四类实战利用手法详解

1. 项目概述:CSP不是铁壁,而是可被理解、可被分析、可被绕过的策略体系“CSP Bypass”这个词在渗透测试和Web安全研究圈里,几乎等同于一次对开发者安全意识的现场压力测试。它不制造漏洞,却能放大漏洞的价值;它不依赖服…

2026/10/17 11:32:28 阅读更多 →
Vue高德地图动态绘制路线与轨迹巡航实战:从坐标转换到动画性能优化

Vue高德地图动态绘制路线与轨迹巡航实战:从坐标转换到动画性能优化

做后台管理系统这么多年,我接到过最典型的“地图需求”就是标题里这个:高德地图动态绘制路线,轨迹巡航,还指定要用 Vue。第一次听可能觉得不就是画一条线加个小车跑吗,真做完才发现里面全是细节:坐标要转换…

2026/10/17 11:32:28 阅读更多 →
STM32F103移植W5500 ioLibrary:SPI驱动与socket通信实战

STM32F103移植W5500 ioLibrary:SPI驱动与socket通信实战

简介:面向基于STM32F103RCT6等MINISTM32平台的嵌入式开发者,这套W5500 ioLibrary移植工程包含完整的驱动适配代码,可直接参考使用。W5500是集成SPI接口的硬核以太网控制器,自带TCP/IP协议栈,配合STM32的SPI外设即可实现…

2026/10/17 11:31:27 阅读更多 →

日新闻

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

简介:《DeepSeek使用方法.pdf》是一份面向DeepSeek入门及进阶用户的完整使用指南,重点围绕V3与R1两款模型的能力差异与适用场景展开,帮助读者根据任务类型与成本选择合适的模型。资源共1个PDF文件,压缩包大小约311KB,篇…

2026/10/17 0:00:25 阅读更多 →
200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

简介:这是一份聚焦DeepSeek提示词优化的《200Deepseek润色指令》PDF文档,共收录两百余条可直接套用的润色指令,涵盖语法修正、风格统一、逻辑梳理、表达精炼等维度,并针对商务写作、学术论文、广告文案等场景给出差异化建议。文档…

2026/10/17 0:00:25 阅读更多 →
OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

简介:本资源是一份基于OpenCV的本科课程设计完整报告,面向计算机视觉初学者、图像处理学习者及高校通信/信息类专业学生,解决物体智能计数与检测结果结构化记录的实际问题。项目覆盖图像预处理、轮廓检测、边界框绘制、轨迹栏交互式参数调节、…

2026/10/17 0:00:25 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/16 21:35:51 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/17 1:44:59 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 21:54:38 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →