双指针算法详解:原理、应用场景及代码示例

文章目录

      • 双指针算法概述
      • 主要应用场景及实现思路
        • 1. 数组排序后的两数之和
        • 2. 链表中环的检测
        • 3. 滑动窗口
        • 4. 合并两个有序数组
        • 5. 移除数组中的重复元素
      • 总结

双指针算法概述

原理
双指针算法的核心在于使用两个指针遍历数据结构,而不是单个指针。这种方法在某些情况下可以显著减少时间复杂度,特别是在处理数组和链表时。

主要应用场景及实现思路

1. 数组排序后的两数之和

应用场景

  • 在已排序的数组中查找两个数,使它们的和等于特定的目标值。
  • 适用于需要高效查找特定组合的情况。

实现思路

  • 初始化两个指针,一个指向数组的起始位置(左指针),另一个指向数组的末尾位置(右指针)。
  • 计算两个指针所指向元素的和。
  • 根据和与目标值的比较结果,调整指针位置:
    • 如果和小于目标值,移动左指针向右。
    • 如果和大于目标值,移动右指针向左。
    • 如果和等于目标值,返回指针的位置。
  • 继续调整指针位置,直到找到答案或两个指针相遇。

代码示例

def two_sum_sorted(arr, target):left, right = 0, len(arr) - 1while left < right:current_sum = arr[left] + arr[right]if current_sum == target:return [left, right]elif current_sum < target:left += 1else:right -= 1return []# 测试
arr = [1, 2, 3, 4, 6]
target = 10
print(two_sum_sorted(arr, target))  # 输出: [3, 4]
2. 链表中环的检测

应用场景

  • 判断链表中是否存在环。
  • 适用于防止无限循环和确保链表结构的正确性。

实现思路

  • 使用两个指针,一个慢指针每次前进一步,一个快指针每次前进两步。
  • 如果链表中存在环,快指针最终会追上慢指针。
  • 如果快指针到达链表末尾(即 fastfast.nextNone),则说明链表中没有环。

代码示例

class ListNode:def __init__(self, x):self.val = xself.next = Nonedef has_cycle(head):if not head or not head.next:return Falseslow = headfast = head.nextwhile fast and fast.next:if slow == fast:return Trueslow = slow.nextfast = fast.next.nextreturn False# 测试
# 创建一个带有环的链表
node1 = ListNode(1)
node2 = ListNode(2)
node3 = ListNode(3)
node4 = ListNode(4)
node1.next = node2
node2.next = node3
node3.next = node4
node4.next = node2  # 创建环print(has_cycle(node1))  # 输出: True
3. 滑动窗口

应用场景

  • 解决字符串或数组中子串/子数组的问题。
  • 特别适用于需要找到满足某些条件的最小子数组长度或最大和等情况。

实现思路

  • 使用两个指针作为窗口的两端,根据条件调整窗口大小。
  • 当窗口满足条件时,尝试缩小窗口以寻找更优解。
  • 通过不断调整窗口的位置和大小,直到找到满足条件的最佳解。

代码示例

from collections import Counterdef min_window(s, t):need = Counter(t)missing = len(t)left, start, end = 0, 0, 0for right, char in enumerate(s):if need[char] > 0:missing -= 1need[char] -= 1if missing == 0:while left < right and need[s[left]] < 0:need[s[left]] += 1left += 1if end == 0 or right - left < end - start:start, end = left, right + 1need[s[left]] += 1missing += 1left += 1return s[start:end]# 测试
s = "ADOBECODEBANC"
t = "ABC"
print(min_window(s, t))  # 输出: "BANC"
4. 合并两个有序数组

应用场景

  • 将两个已排序的数组合并成一个新的有序数组。
  • 适用于需要高效合并多个有序数据集的情况。

实现思路

  • 分别为两个数组设置指针,从头开始比较两个数组的当前元素。
  • 将较小的元素放入结果数组中,并移动对应的指针。
  • 继续这一过程,直到其中一个数组的所有元素都被处理完毕。
  • 最后,如果还有剩余未处理的数组,则将其余部分直接复制到结果数组的末端。

代码示例

def merge_sorted_arrays(arr1, arr2):merged = []i, j = 0, 0while i < len(arr1) and j < len(arr2):if arr1[i] < arr2[j]:merged.append(arr1[i])i += 1else:merged.append(arr2[j])j += 1# 添加剩余的元素while i < len(arr1):merged.append(arr1[i])i += 1while j < len(arr2):merged.append(arr2[j])j += 1return merged# 测试
arr1 = [1, 3, 5]
arr2 = [2, 4, 6]
print(merge_sorted_arrays(arr1, arr2))  # 输出: [1, 2, 3, 4, 5, 6]
5. 移除数组中的重复元素

应用场景

  • 在非递减数组中去除重复出现的元素,使每个元素只出现一次。
  • 适用于需要高效去重的情况。

实现思路

  • 使用两个指针,一个用于追踪当前处理到的非重复元素的位置,另一个用于遍历整个数组。
  • 遍历过程中,如果发现当前元素与前一个元素不同,则将其放置在追踪指针的位置,并向前移动追踪指针。
  • 遍历结束后,追踪指针之前的数组部分就是去重后的数组。

代码示例

def remove_duplicates(arr):if not arr:return 0write_pointer = 1  # 写指针,记录下一个非重复元素的位置for read_pointer in range(1, len(arr)):if arr[read_pointer] != arr[read_pointer - 1]:arr[write_pointer] = arr[read_pointer]write_pointer += 1return write_pointer# 测试
arr = [1, 1, 2, 2, 3, 4, 4, 5]
length = remove_duplicates(arr)
print(arr[:length])  # 输出: [1, 2, 3, 4, 5]

总结

双指针算法通过巧妙地利用两个指针来遍历数据结构,能够在多种场景下提供高效的解决方案。以下是双指针算法的一些关键点:

  • 时间复杂度:通常可以将时间复杂度从 O(n^2) 降低到 O(n),显著提高效率。
  • 空间复杂度:大多数情况下,双指针算法的空间复杂度为 O(1),因为不需要额外的存储空间。
  • 灵活性:适用于多种数据结构和问题类型,包括数组、链表、字符串等。

希望这些详细的讲解和代码示例能帮助你更好地理解和应用双指针算法。如果你有任何进一步的问题或需要更多的示例,请随时告诉我。

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

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

相关文章

vue2-代理服务器插槽

解决跨域问题 配置代理服务器 代理服务器位于前端应用(客户端)和真实的后端服务器之间。当配置了代理服务器后&#xff0c;前端应用的请求不再直接发送到后端服务器&#xff0c;而是发送到代理服务器。代理服务器在接收到请求后&#xff0c;会根据预先配置的规则将请求转发到真…

12 —— Webpack中向前端注入环境变量

需求&#xff1a;开发模式下打印语句生效&#xff0c;生产模式下打印语句失效 使用Webpack内置的DefinePlugin插件 const webpack require(webpack) module.exports { plugins: [ new webpack.DefinePlugin({ process.env.NODE_ENV:JSON.stringify(process.env.NODE_ENV) }…

【vba源码】导入excel批注信息

Hi&#xff0c;大家好呀&#xff01; 又到了一周一分享的时间&#xff0c;上周繁忙的我都没有给大家直播&#xff0c;视频也没更新&#xff0c;那这周大家放心&#xff0c;都会给大家更新&#xff0c;今天我们来讲点啥呢&#xff1f;每周找优质的内容给大家更新是我最最痛苦的…

Java设计模式 —— Java七大设计原则详解

文章目录 前言一、单一职责原则1、概述2、案例演示 二、接口隔离原则1、概述2、案例演示 三、依赖倒转原则1、概述2、案例演示 四、里氏替换原则1、概述2、案例演示 五、开闭原则1、概述2、案例演示 六、迪米特法则1、概述2、案例演示 七、合成/聚合复用原则1、概述2、组合3、聚…

服务器数据恢复—DS5300存储硬盘指示灯亮黄灯的数据恢复案例

服务器存储数据恢复环境&#xff1a; 某单位一台某品牌型号为DS5300的服务器存储&#xff0c;1个机头4个扩展柜&#xff0c;底层是2组分别由数十块硬盘组建的RAID5阵列。存储系统上层一共分了11个卷。 服务器存储故障&分析&#xff1a; 存储设备上一组raid5阵列上的2块磁盘…

跨域资源共享 (CORS)

一、什么是跨域&#xff1f; 跨域是指浏览器发起的请求&#xff0c;其目标服务器与当前页面的来源&#xff08;域名、协议、端口&#xff09;不一致。例如&#xff1a; 同源请求&#xff1a; 页面和接口来源一致&#xff0c;比如&#xff1a; 页面地址&#xff1a;http://exa…

资源控制器--laravel进阶篇

laravel的控制器当中有个资源控制器,这个比较好用。 创建资源控制器 php artisan make:controller PhotoController --resource 创建个路由来使用该资源控制器 use App\Http\Controllers\PhotoController; Route::resource(photos, PhotoController::class); 隐式模型绑定不…

Cloud Native 云原生后端的开发注意事项

在云原生后端开发里&#xff0c;数据管理和存储这块得好好弄。数据库选型得综合考虑&#xff0c;像关系型数据有复杂查询需求就选 MySQL、PostgreSQL&#xff0c;海量非结构化数据就可以考虑 MongoDB、Cassandra 这些。设计数据库得遵循规范化原则&#xff0c;像设计电商订单表…

Mac vscode 激活列编辑模式

列编辑模式在批量处理多行文本时&#xff0c;非常有效&#xff0c;但 vscode 默认情况下&#xff0c;又没有激活&#xff0c;因此记录一下启动方法&#xff1a; 激活列编辑模式 然后就可以使用 Alt&#xff08;Mac 上是 Option 或 Command 键&#xff09; 鼠标左键 滑动选择了…

c#使用高版本8.0步骤

一、找到项目所在怒路&#xff0c;记事本打开.proj文件。 二、记事本打开此文件&#xff0c;<PropertyGroup>后面加入如下语句&#xff1a; <LangVersion>8.0</LangVersion> 关闭并保存。 根据提示全部重新加载即可。

【蓝桥杯C/C++】深入解析I/O高效性能优化:std::ios::sync_with_stdio(false)

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: 蓝桥杯C/C 文章目录 &#x1f4af;前言&#x1f4af;C 语言与 C 语言的输入输出对比1.1 C 语言的输入输出1.2 C 语言的输入输出 &#x1f4af; std::ios::sync_with_stdio(false) 的作用与意义2.1 什么是 std::ios::sync_with_st…

OpenCV 计算图像清晰度

文章目录 一、简介二、实现代码三、实现效果一、简介 我们往往怎么定义一个图像的清晰度呢,通常来讲一个图像的清晰度越高,其图像细节越丰富,也就是说我们通常可以通过图像的高频信息(如边缘或噪声)来衡量。OK,既然如此,这里可以使用 拉普拉斯算子(cv::Laplacian)先对…

浏览器的事件循环机制

一、请简述浏览器的事件循环机制&#xff08;Event Loop&#xff09;基本原理 浏览器的事件循环机制是用于协调处理 JavaScript 中的异步任务与同步任务执行顺序的一种机制&#xff0c;它确保了代码能够按照合理的顺序执行&#xff0c;避免阻塞页面渲染等情况。其基本原理如下…

Oracle-表空间/用户的创建与使用

-- 对象 -- 需要create的都是对象 已学的对象&#xff1a;表 table -- 普通用户 只能查询user开头的数据字典 select tablespace_name from user_tablespaces; -- dba用户才能够查询 select tablespace_name from dba_tablespaces; -- 创建表空间&#xff08;需要管理员…

GaussDB 华为高斯数据库

GaussDB 是华为推出的一款企业级分布式数据库&#xff0c;旨在为企业提供高效、可靠、安全的数据库服务。GaussDB 基于华为在数据库领域的多年积累&#xff0c;结合人工智能技术和分布式架构&#xff0c;支持多种场景的数据存储与管理需求&#xff0c;是云计算、大数据、人工智…

【Word】一键批量引用论文上标——将正文字体改为上标格式

【Word】一键批量引用论文上标——将正文字体改为上标格式 写在最前面Word一键批量引用论文上标技巧分享核心思路&#xff1a;Word 替换功能 通配符步骤详解1. 打开 Word 替换功能2. 输入通配符模式3. 设置替换格式为上标4. 批量替换 实际效果展示技巧扩展 &#x1f308;你好呀…

C#里怎么样访问文件时间

C#里怎么样访问文件时间 文件时间也是一个关键信息, 因为很多数据处理需要时间来判断数据的有效性,比如股票中的股价, 它是的权重,是随着时间递减的。 一般来说,超过5年以上的数据,都是可以删除掉了。 或者说超过三年的数据,就需要压缩保存了,这样可以省掉很多磁盘空…

SAP 零售方案 CAR 系统的介绍与研究

前言 当今时代&#xff0c;零售业务是充满活力和活力的业务领域之一。每天&#xff0c;由于销售运营和客户行为&#xff0c;它都会生成大量数据。因此&#xff0c;公司迫切需要管理数据并从中检索见解。它将帮助公司朝着正确的方向发展他们的业务。 这就是为什么公司用来处理…

系统调用介绍

系统调用是操作系统提供给用户程序调用的一组功能接口&#xff0c;它允许用户程序请求操作系统执行一些特定的操作或服务。这些操作通常涉及对系统资源的访问和管理&#xff0c;如文件管理、进程控制、设备管理等。系统调用是用户程序和操作系统之间的桥梁&#xff0c;它使得用…

【深度学习之一】2024最新pytorch+cuda+cudnn下载安装搭建开发环境

兵马未动&#xff0c;粮草先行。作为深度学习的初学者&#xff0c;快速搭建一个属于自己的开发环境就是头等大事&#xff0c;可以让我们节省许多的时间。这一期我们主要讲一讲2024年最新pytorchcudacudnn下载安装搭建开发环境&#xff0c;以及安装过程中可能遇到的一些问题以及…