【数据结构与算法Trip第3站】双指针

我们来详细讲解一下算法中非常常用且重要的技巧——双指针法。

这是一个概念清晰但应用极其广泛的技术,掌握它能帮助你高效解决许多问题。

一、什么是双指针法?

核心思想:顾名思义,就是在遍历对象(通常是数组或链表)时,使用两个相同方向或相反方向的指针(索引)进行扫描,通过指针的移动和相互配合来解决问题,从而避免不必要的循环,将暴力解法的时间复杂度优化到 O(n) 级别。

为什么有效? 它通过巧妙地利用问题的内在逻辑(如有序性),避免了大量的重复计算,将复杂度从 O(n²) 降低到 O(n)。

二、双指针的三种常见类型

双指针法主要有三种常见的应用形式,我们结合例子来理解。

1. 快慢指针(前后指针)

两个指针从同一侧开始遍历,但移动速度不同(例如,一个一次走一步,一个一次走两步)。常用于链表问题。

典型问题:判断链表是否有环
• 思路:设置两个指针 slow 和 fast,起始位置都在链表头。

◦   slow 每次向后移动一个节点。◦   fast 每次向后移动两个节点。

• 判断:

◦   如果链表中没有环,fast 指针会先到达链表尾部(遇到 null)。◦   如果链表中有环,fast 指针最终会追上 slow 指针(fast == slow),就像在环形跑道上赛跑一样。

• 代码示例 (Python)
class ListNode:
def init(self, x):
self.val = x
self.next = None

def hasCycle(head: ListNode) -> bool:if not head or not head.next:return Falseslow = headfast = head.nextwhile slow != fast:# 如果fast或fast.next为空,说明到了链表末尾,无环if not fast or not fast.next:return Falseslow = slow.nextfast = fast.next.next # fast每次走两步# 如果slow等于fast,说明有环return True

• 其他应用:寻找链表的中间节点、寻找链表的倒数第 k 个节点。

2. 左右指针(对撞指针)

两个指针分别从序列的两端向中间移动,直到它们相遇。前提通常是序列是有序的。

典型问题:两数之和 II - 输入有序数组 (LeetCode 167)
题目:给定一个已按升序排列的整数数组 numbers,请你从数组中找出两个数满足相加之和等于目标数 target。假设每个输入只对应唯一的答案,且不可以重复使用相同的元素。

• 暴力法:两层循环,时间复杂度 O(n²)。

• 双指针法:利用有序这个关键特性。

◦   步骤:1.  初始化:左指针 left = 0,右指针 right = len(numbers) - 1。2.  循环条件:while left < right。3.  计算 sum_val = numbers[left] + numbers[right]。4.  判断:▪   如果 sum_val == target,找到答案,返回 [left+1, right+1] (题目要求索引从1开始)。▪   如果 sum_val < target,说明总和太小,需要增大。因为数组有序,所以将 left 右移(left += 1)。▪   如果 sum_val > target,说明总和太大,需要减小。将 right 左移(right -= 1)。

• 代码示例 (Python)
def twoSum(numbers: List[int], target: int) -> List[int]:
left, right = 0, len(numbers) - 1

    while left < right:s = numbers[left] + numbers[right]if s == target:return [left + 1, right + 1]elif s < target:left += 1else:right -= 1return [-1, -1] # 题目保证有解,这行不会执行

• 为什么正确? 每次移动都排除了大量不可能的解,缩小了搜索范围。

• 其他应用:二分查找、反转字符串、三数之和、盛最多水的容器。

3. 滑动窗口(也是双指针的一种)

两个指针形成一个窗口(区间),通过移动指针的起始位置来动态地扩展或收缩这个窗口。常用于子串、子数组问题。

典型问题:长度最小的子数组 (LeetCode 209)
题目:给定一个含有 n 个正整数的数组和一个正整数 target。找出该数组中满足其和 ≥ target 的长度最小的连续子数组,并返回其长度。

• 思路:

◦   使用两个指针 left 和 right,代表窗口的左右边界。◦   right 指针向右移动,扩大窗口,直到窗口内的元素总和 >= target。◦   一旦满足条件,记录当前窗口长度,然后 left 指针向右移动,收缩窗口,尝试寻找更小的窗口,同时更新窗口和。◦   重复上述过程,直到 right 到达数组末尾。

• 代码示例 (Python)
def minSubArrayLen(target: int, nums: List[int]) -> int:
left = 0
total = 0
min_len = float(‘inf’) # 初始化为一个极大值

    # right指针遍历整个数组,作为窗口的右边界for right in range(len(nums)):total += nums[right] # 扩大窗口,加入right指向的元素# 当窗口总和满足条件时,收缩左边界while total >= target:# 更新最小长度current_len = right - left + 1min_len = min(min_len, current_len)# 缩小窗口,从总和里减去left指向的元素,并移动lefttotal -= nums[left]left += 1return 0 if min_len == float('inf') else min_len

• 其他应用:字符串的排列、找到字符串中所有字母异位词、最小覆盖子串。

三、总结与要点

类型 指针方向 典型应用 关键特点

快慢指针 同向,速度不同 链表判环,找中点 常用于链表数据结构

左右指针 相向而行 有序数组的两数之和,反转数组 序列有序是关键前提

滑动窗口 同向,一前一后 最小长度子数组,字符串匹配 维护一个动态变化的区间

使用双指针法的核心要点:

  1. 分析问题特性:先思考暴力解法,再看数据是否有有序、单调性等特性,能否用指针移动来避免重复计算。
  2. 确定指针含义:明确每个指针代表什么(如链表的节点、数组的索引)。
  3. 确定移动规则:想清楚在什么条件下移动哪个指针,以及移动多少。
  4. 注意边界条件:仔细处理指针越界、相遇、初始位置等情况。

希望这个详细的讲解能帮助你彻底理解双指针法!多加练习是掌握它的最好方式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/96419.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/96419.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

时序数据库选型指南:基于大数据视角的IoTDB应用优势分析详解!

目录 一、时序数据库选型的基本原则 1.1 数据特征与需求分析 1.1.1 数据规模与写入负载 1.1.2 查询需求 1.1.3 数据保留与归档策略 1.1.4 系统扩展性与高可用性 1.2 技术架构与系统性能评估 1.2.1 写入性能 1.2.2 查询性能 1.2.3 数据压缩能力 1.2.4 高可用性与灾备…

缓存三大劫攻防战:穿透、击穿、雪崩的Java实战防御体系(三)

第三部分&#xff1a;缓存雪崩——大量key失效引发的“系统性崩溃” 缓存雪崩的本质是“大量缓存key在同一时间失效&#xff0c;或缓存集群整体故障”&#xff0c;导致请求全量穿透至DB&#xff0c;引发“系统性崩溃”。 案例4&#xff1a;电商首页的“批量过期”灾难 故障现场…

解决docker配置了镜像源但还会拉取官方镜像源的问题

&#x1f3d3;我们有时候虽然配置了Docker国内镜像源&#xff0c;但是还是会绕过去请求官方镜像源&#xff08;docker: Error response from daemon: Get "https://registry-1.docker.io/v2/": context deadline exceeded&#xff09;&#xff0c;现在我们就来解决一…

R语言水文、水环境模型优化:从最速上升法、岭分析到贝叶斯优化与异方差处理,涵盖采样设计、代理模型与快速率定等

在水利工程、环境治理、生态保护、机械设计与航天航空等现代工业与科学领域&#xff0c;数学模型已成为不可或缺的核心分析、预测与决策工具。然而&#xff0c;随着系统复杂性的日益增长&#xff0c;模型构建的精确性、参数率定的效率以及不确定性量化的重要性被提到了前所未有…

关于数据采集与处理心得(一)

目前所实践的经验告知我&#xff01;1. 别企图妄想一个脚本解决所有问题要学会对问题分解&#xff0c;编写多个脚本一步步将问题解决&#xff0c;如果每一个步骤都为了下一个阶段的成果打地基&#xff0c;也是非常OK的。同时要尽可能将每一个编写的脚本都尽到最大的利用率2. 编…

IvorySQL 适配 LoongArch® 龙架构

IvorySQL 社区很高兴向您宣布&#xff0c;IvorySQL 已成功适配LoongArch 龙架构&#xff0c;为国产数据库与国产芯片的深度融合迈出了坚实一步。这一里程碑标志着 IvorySQL 在推动国产化生态建设、赋能信创产业方面取得了重大突破&#xff0c;为用户提供更高效、稳定、安全的数…

数据库分库分表是考虑ShardingSphere 还是Mycat?

http://www.mycat.org.cn/ https://shardingsphere.apache.org/ 这是一个非常核心且优秀的问题。在选择 ShardingSphere 和 Mycat 之间&#xff0c;对于游戏这种高性能、高复杂度的场景&#xff0c;目前行业内的主流选择和发展趋势毫无疑问是 ShardingSphere。 我会为你详细对…

mysql分库分表数据量核查问题

场景&#xff1a; 使用分库分表的业务有时分库数量几百甚至上千&#xff0c;当主管需要查询每个库中的数据&#xff0c;掌握数据分布情况。要你查看哪些库中的表数量大于某个量级的给找出来 &#xff0c;你会怎么做。 例子 &#xff1a; mysql库数量&#xff1a;db_xx_devicein…

python之socket网络编程

引言 在互联网时代&#xff0c;网络编程已经成为开发人员必备的技能之一。无论是Web开发、实时通信还是分布式计算&#xff0c;都离不开网络编程的支持。Python提供的socket模块为我们提供了简洁而强大的接口&#xff0c;可以轻松实现客户端和服务器之间的通信。 Socket编程是网…

WPF Telerik.Windows.Controls.Data.PropertyGrid 自定义属性编辑器

1.AI帮忙定义新用户控件 2.在属性上添加TelerikEditorAttribute特性 private ObservableCollection<string> _axisOrder;[Display(Description "点位", GroupName "通用", Name "轴&顺序", Order 1)][DataMember][TelerikEditorAt…

【超详细】别再看零散的教程了!一篇搞定Gitee从注册、配置到代码上传与管理(内含避坑指南最佳实践)

&#x1f525;个人主页&#xff1a;艾莉丝努力练剑 ❄专栏传送门&#xff1a;《C语言》、《数据结构与算法》、C语言刷题12天IO强训、LeetCode代码强化刷题、洛谷刷题、C/C基础知识知识强化补充、C/C干货分享&学习过程记录 &#x1f349;学习方向&#xff1a;C/C方向学习者…

43.shell脚本循环与函数

shell脚本循环与函数 for 循环 for 循环用于一次性读取多个信息&#xff0c;逐一对信息进行操作处理&#xff0c;特别适合处理有范围的数据 语法 for 变量名 in 取值列表 do命令序列 done批量创建用户 #!/bin/bashtouch /root/users.txt echo aka blues cloe dio foks > /ro…

模型部署:(四)安卓端部署Yolov8-v8.2.99实例分割项目全流程记录

模型部署&#xff1a;&#xff08;四&#xff09;安卓端部署Yolov8-v8.2.99实例分割项目全流程记录1、下载ncnn2、下载opencv-mobile3、文件拷贝4、andorid_studio相关配置5、文件内参数设置5、重构项目&#xff1a;6、打包apk7、部署自己训练的实例分割模型1、下载ncnn 地址&…

高并发、低延迟全球直播系统架构

一、 核心架构图 整个系统的数据流和工作流程如下图所示&#xff0c;它清晰地展示了从主播推流到观众观看的完整过程&#xff1a; #mermaid-svg-QzNpj0DWxd5FERPC {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-QzN…

AWS strands agents 当智能体作为独立服务/容器部署时,它们无法共享进程内状态

当智能体作为独立服务/容器部署时&#xff0c;它们无法共享进程内状态。 以下是针对分布式部署中动态内存库的生产就绪解决方案&#xff1a;1. 基于外部存储的内存库基于 DynamoDB 的共享内存import boto3 from strands import Agent, tool from typing import Dict, Any impor…

第五节 JavaScript——引用类型、DOM/BOM 与异步编程

JavaScript 的第五节课通常会深入探讨 ​​引用类型、DOM 操作、BOM 操作、事件处理以及异步编程​​ 等核心概念。这些知识能让你创建动态交互丰富的网页。下面我将详细讲解这些内容并提供示例。 🚀 JavaScript 第五节:引用类型、DOM/BOM 与异步编程 ⚡ 一、引用类型 引…

使用Pycharm进行远程ssh(以Featurize为例)

使用Pycharm进行远程ssh&#xff08;以Featurize为例&#xff09;文章目录介绍应用背景远程连接Python连接Jupyter介绍应用背景 在使用Pycharm 专业版的时候进行远程ssh连接服务器&#xff08;Featurize&#xff09;的Python解释器和Jupyter 远程连接Python 打开Pycharm点击…

深入研究:ClickHouse中arrayExists与hasAny在ORDER BY场景下的性能差异

最近公司大数据情况下ClickHouse查询性能极差&#xff0c;后来发现在大数据量ORDER BY场景下&#xff0c;arrayExists(x -> x in ...)比hasAny性能快10倍&#xff01;&#xff01;&#xff01;&#xff01; 一、问题重述与研究背景 在大数据量 ORDER BY场景下&#xff0c;…

Spring AI (二)结合Mysql做聊天信息存储

上文讲了&#xff0c;用Spring ai做简单的聊天功能&#xff0c;没看过的可以查看下 Spring AI结合豆包模型 这里简单结合下Jdbc做下聊天记录的存储和查询&#xff0c;让对话变的更智能。 首先是Pom的支持 <dependency><groupId>org.springframework.ai</grou…

【docker】data-root 数据迁移(防止无法加载镜像和容器问题)

操作系统&#xff1a;ubuntu 24.04 docker版本&#xff1a;docker-ce 28.1.1 目标&#xff1a;将/var/lib/docker 的数据迁移到/data/docker停止docker sudo systemctl stop docker.socket sudo systemctl stop docker这个步骤一定要做&#xff0c;否则容易导致数据不一致。 rs…