你需要掌握的算法:快慢指针

news2024/12/30 1:44:25

文章目录

    • 前言
    • 龟兔赛跑
      • 乌龟能否追上兔子
      • 乌龟与兔子在何处相遇
      • 龟兔问题的推论
    • 快慢指针
      • 基础概念
      • 发展历史
    • 快慢指针的应用
      • 检测链表是否有环
      • 找到链表的中间节点
      • 计算链表的环长度
      • 找到链表环的入口节点
    • 小结

前言

在处理链表数据结构时,快慢指针是一种非常高效的算法技巧。它通过使用两个指针以不同的速度移动来解决链表中的各种问题,如检测链表是否有环、找到链表的中间节点、计算环的长度等。本文将详细介绍快慢指针的基本概念、主要应用及示例代码,帮助大家在实际开发中更好地理解和应用快慢指针。

龟兔赛跑

“龟兔赛跑” 的故事相信大家都不陌生,今天我们研究一个另类的龟兔赛跑。

乌龟和兔子同时从直线跑道的起点出发,乌龟的速度是 v v v,兔子的速度是 2 v 2v 2v,现兔子已经进入环形跑道(进入环形跑道之后,只能沿着环形跑道运动)。

请问乌龟是否能追上兔子?乌龟若能追上兔子,那么乌龟和兔子将在何处相遇?

乌龟能否追上兔子

乌龟一定能追上兔子。因为兔子一直在环形跑道中,当乌龟进入环形跑道之后也将沿环形跑道不断运动。由于乌龟与兔子的速度不相等,两者不能保持相对静止,所以二者总会在某一位置相遇。

乌龟与兔子在何处相遇

乌龟与兔子在何处相遇,我们需要进行数学推导。

倘若直行跑道的总长度是 a a a,环形跑道的总长度是 h h h

假设乌龟与兔子未来在 D D D 点相遇,环形跑道起点到 D D D 点的距离为 b b b D D D 点回到起点的距离为 c c c

则有: h = b + c h = b + c h=b+c

当乌龟与兔子相遇时,有:

乌龟的运动距离是: a + b a + b a+b

兔子的运动距离是: a + n h + b = a + n ( b + c ) + b a + nh + b = a + n(b + c) + b a+nh+b=a+n(b+c)+b n n n 表示环形跑道的圈数

因为乌龟的速度是 v v v,兔子的速度是 2 v 2v 2v,则有:兔子的运动距离恒为乌龟运动距离的两倍

2 ( a + b ) = a + n ( b + c ) + b 2(a + b) = a + n(b + c) + b 2(a+b)=a+n(b+c)+b

推导出:

a = c + ( n − 1 ) ( b + c ) a = c + (n - 1)(b + c) a=c+(n1)(b+c),即:直行跑道的长度等于从相遇点 D D D 到入环点的距离加上 n − 1 n - 1 n1 圈环长。

这个结果直观上并没有太大的意义。我们现做两个假设:

假设一:此时乌龟回到直线跑道的起点,兔子依旧在相遇点 D D D,现在它们重新都以速度 v v v 运动。

此时会出现:当乌龟再次运动到入环点时,兔子也刚好重新运动到入环点。

假设二:兔子静止在相遇点 D D D,乌龟继续以速度 v v v 运动

此时会出现:当乌龟再次和兔子相遇时,刚好是环的长度

龟兔问题的推论

通过研究龟兔问题我们可以有以下几个推论:

  1. 龟兔问题可以用于检测环形(乌龟和兔子如果能够相遇一定存在环)
  2. 若有环,可以找出环的入口点
  3. 若有环,可以计算出环的长度

快慢指针

基础概念

快慢指针(Two Pointers/Floyd’s Tortoise and Hare Algorithm)是一种经典的算法技巧,用于解决链表、数组等数据结构中的问题。该方法最著名的应用是检测链表中的环,通常称为弗洛伊德循环检测算法(Floyd’s Cycle Detection Algorithm),或龟兔赛跑算法。它使用两个指针:慢指针和快指针。

  • 慢指针:每次移动一步。
  • 快指针:每次移动两步。

即,快指针是慢指针速度的 2 2 2 倍( v fast = 2 v slow v_{\text{fast}} = 2v_{\text{slow}} vfast=2vslow

发展历史

  • 快慢指针算法最早由罗伯特·弗洛伊德(Robert W. Floyd)在 1967 年提出。他在论文中描述了如何使用快慢指针解决循环检测问题。
  • 在快慢指针方法被广泛应用后,许多编程教材和算法书籍将该算法称为龟兔赛跑算法(Tortoise and Hare Algorithm),灵感来源于古希腊伊索寓言中的“龟兔赛跑”故事。在这算法中,慢指针代表 “乌龟”,快指针代表 “兔子”,虽然兔子(快指针)比乌龟(慢指针)快,但它绕圈时最终会被乌龟追上。

快慢指针的应用

检测链表是否有环

使用快慢指针可以有效地检测链表中是否存在环。快指针每次移动两步,慢指针每次移动一步。如果链表中存在环,则快指针和慢指针最终会在环内相遇。如果链表没有环,则快指针会到达链表末尾。

public boolean detectCycle(ListNode head) {
    // 初始化两个指针:slow 和 fast,都指向链表的头节点
    ListNode slow = head, fast = head;

    // 使用 while 循环遍历链表,条件是 fast 不能为 null 且 fast.next 不能为 null
    while (fast != null && fast.next != null) {
        slow = slow.next;           // slow 指针每次走一步
        fast = fast.next.next;      // fast 指针每次走两步

        // 检查快指针和慢指针是否相遇(即 slow == fast)
        if (slow == fast) {
            // 如果相遇,说明链表中存在环
            return true;
        }
    }

    return false;
}

找到链表的中间节点

使用快慢指针可以高效地找到链表的中间节点。慢指针每次移动一步,快指针每次移动两步。当快指针到达链表末尾时,慢指针正好到达中间节点。

public ListNode findMiddle(ListNode head) {
    // 初始化两个指针:slow 和 fast,都指向链表的头节点
    ListNode slow = head, fast = head;

    // 使用 while 循环遍历链表,条件是 fast 不能为 null 且 fast.next 不能为 null
    while (fast != null && fast.next != null) {
        slow = slow.next;           // slow 指针每次走一步
        fast = fast.next.next;      // fast 指针每次走两步
    }

    // 当 fast 走到链表的末尾时,slow 指针正好位于链表的中间节点
    return slow; // 返回中间节点
}

计算链表的环长度

在检测到链表中存在环后,可以使用快慢指针计算环的长度。首先,快慢指针相遇时,计算环中节点的数量,直到再次遇到快指针。

public int calculateCycleLength(ListNode head) {
    // 初始化快慢指针,slow 和 fast 都指向链表的头节点
    ListNode slow = head, fast = head;

    // 变量 hasCycle 用来标记是否检测到环
    boolean hasCycle = false;

    // 检测环的存在
    // 使用 while 循环遍历链表,条件是 fast 和 fast.next 不能为 null
    while (fast != null && fast.next != null) {
        slow = slow.next;           // slow 每次走一步
        fast = fast.next.next;      // fast 每次走两步

        // 如果 slow 和 fast 相遇,说明存在环
        if (slow == fast) {
            hasCycle = true;        // 标记检测到环
            break;                  // 退出循环,开始计算环的长度
        }
    }

    // 如果没有检测到环,直接返回 0,表示没有环
    if (!hasCycle) return 0;

    // 计算环的长度
    int length = 0;                // 初始化长度变量为 0

    // 使用 do-while 循环遍历环,直到 slow 再次和 fast 相遇
    do {
        slow = slow.next;          // slow 每次走一步
        length++;                  // 每走一步,环的长度加 1
    } while (slow != fast);        // 当 slow 再次与 fast 相遇时,说明遍历了一圈

    // 返回环的长度
    return length;
}

找到链表环的入口节点

在检测到链表中有环之后,可以通过快慢指针找到环的入口节点。将一个指针从链表头部开始移动,另一个指针从环内相遇点开始移动,两者相遇的节点即为环的入口。

public ListNode findCycleStart(ListNode head) {
    // 初始化两个指针 slow 和 fast,都指向链表的头节点
    ListNode slow = head, fast = head;

    // 开始遍历链表,使用快慢指针法来检测环的存在
    while (fast != null && fast.next != null) {
        slow = slow.next;           // slow 每次走一步
        fast = fast.next.next;      // fast 每次走两步

        // 当 slow 和 fast 相遇时,说明链表中存在环
        if (slow == fast) {

            // 找到环之后,初始化一个新的指针 entry,指向链表的头节点
            ListNode entry = head;

            // 现在我们有两个指针:一个从头开始(entry),一个从相遇点开始(slow)
            // 两个指针每次都向前走一步,直到它们相遇,那个相遇点就是环的入口
            while (entry != slow) {
                entry = entry.next; // entry 每次向前走一步
                slow = slow.next;   // slow 也每次向前走一步
            }

            // 两个指针在环的入口相遇,返回该入口节点
            return entry;
        }
    }

    // 如果没有检测到环,返回 null,说明链表中没有环
    return null;
}

小结

快慢指针是一种高效的算法技巧,特别适用于链表问题。它通过两个指针以不同速度移动来解决问题,可以有效地检测链表中的环、找到中间节点、计算环的长度以及找到环的入口节点。

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

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

相关文章

鸡尾酒排序算法

目录 引言 一、概念 二、算法思想 三、图例解释 1.采用冒泡排序: 2.采用鸡尾酒排序: 3.对比总结 四、算法实现 1.代码实现 2.运行结果 3.代码解释 五、总结 引言 鸡尾酒排序(Cocktail Sort),也被称为双向冒…

同一天!蚂蚁集团宣布将发布3款AI新产品!腾讯、零一万物、面壁智能推出最新大模型|AI日报

文章推荐 缓解父母焦虑!详细实测!这些免费AI可以成为孩子提高学习能力的得力助手! 附送试听地址!OpenAI ChatGPT被曝将新增8种语音!英特尔酷睿Ultra 200V正式发布|AI日报 今日热点 蚂蚁将发布三款AI新产…

Zynq7020 SDK 初学篇(4)- PL 端 GPIO

1.开发背景 基于 PS 端 GPIO 的基础上,如何调用 PL 端 GPIO 的输入输出 2.开发需求 PL 端按键控制 PL 端 LED 3.开发环境 Zynq7020 Vivado2017.4 4.实现步骤 4.1 设计配置 这里设置 PIO 数量 3 个 由于 PL 端不像 PS 端一样绑定 GPIO,所以需要对上面…

内容营销服务,照亮您的独特优势,助力业务增长

内容营销公司通常会承诺过高但交付不足,而在Digital Commerce Partners,我们走的是相反的方向。我们会调低(然后超越)预期。 由于我们是Copyblogger的SEO和内容营销代理商,我们知道伟大的事情需要时间——这意味着吸引…

【最新华为OD机试E卷-支持在线评测】通过软盘拷贝文件(200分)多语言题解-(Python/C/JavaScript/Java/Cpp)

🍭 大家好这里是春秋招笔试突围 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-E/D卷的三语言AC题解 💻 ACM金牌🏅️团队| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试E卷,全、新、准,题目覆盖率达 95% 以上,支持…

人工智能安全治理框架导图

资源链接:《人工智能安全治理框架》1.0版发布_中央网络安全和信息化委员会办公室

【Python机器学习】循环神经网络(RNN)——循环网络的记忆功能

文档中的词很少是完全独立的,它们的出现会影响文档中的其他词或者收到文档中其他词的影响: The stolen car sped into the arena. The clown car sped into the arena. 这两句话可能会产生两种完全不同的情感感受。这两个句子的形容词、名词、动词、介词…

算法入门-深度优先搜索2

第六部分:深度优先搜索 104.二叉树的最大深度(简单) 题目:给定一个二叉树 root ,返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1: 输入:ro…

Tomcat配置及Servlet相关

目录 Eclipse配置Tomcat 1.配置服务器运行环境 2.新建服务器 3.新建动态Web项目 4.创建类继承HttpServlet 5.启动服务器 6.测试访问 请求转发与重定向 请求转发 重定向 Servlet的作用域 Servlet生命周期 这里以Eclipse为例,IDEA配置参考:IDE…

若依框架使用MyBatis-Plus中的baseMapper的方法报错Invalid bound statement (not found):

Invalid bound statement (not found): com.ruoyi.system.mapper.hc.HcOrderMapper.selectList 解决方法 MybatisSqlSessionFactoryBean sessionFactory new MybatisSqlSessionFactoryBean(); 使用 MybatisSqlSessionFactoryBean 而非 SqlSessionFactoryBean 的原因 MyBatis-…

卷轴模式系统源码开发之功能技术分析

随着互联网经济的蓬勃发展,电商平台之间的竞争日益激烈。为了吸引和保留用户,许多电商平台开始探索和采用创新的商业模式。其中,“卷轴模式”作为一种结合了积分奖励和任务兑换机制的新颖模式,逐渐受到了业界的关注。本文将从技术…

智能提醒助理系列-小程序分享到朋友圈

本系列文章记录“智能提醒助理”wx公众号 建设历程,记录实践经验、巩固知识点、锻炼总结能力。 本篇介绍微信小程序如何分享到朋友圈,以及遇到的登录无权限问题和解决方案。 一、需求出发点 智能提醒小程序的推广是一个难点,朋友圈是一个必要…

柯桥外语学习生活日语之与台风有关的日语表达

与台风有关的日语表达: 台風が近づいている (たいふうがちかづいている) - 台风正在靠近 台風が上陸する (たいふうがじょうりくする) - 台风登陆 台風の進路 (たいふうのしんろ) - 台风的路径 強い台風 (つよいたいふう) - 强烈的台风 台風の目 (たいふうのめ…

深度学习的模型知识点介绍和总结

关注公众号:『AI学习星球』 算法学习、4对1辅导、论文辅导或核心期刊可以通过公众号滴滴我 文章目录 1. 神经网络基础1.1 人工神经网络(ANN)1.2 介绍下激活函数 2. 卷积神经网络(CNN)2.1 卷积层2.2 池化层2.3 全连接层…

GoogleTest安装以及使用

文章目录 介绍Ubuntu安装centos7 安装gtest使用方法包含gtest/gtest.h头文件使用TEST()宏定义测试用例使用Google Test断言进行值检查使用RUN_ALL_TESTS()宏运行测试 测试代码 介绍 Google Test(也称为gtest)是Google开发的一个用于C的单元测试库。 它允…

OPenCV结构分析与形状描述符(5)查找图像中的连通组件的函数connectedComponents()的使用

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 connectedComponents 函数计算布尔图像的连通组件标签图像。 该函数接受一个具有4或8连通性的二值图像,并返回 N,即标签…

算法入门-深度优先搜索3

第六部分:深度优先搜索 112.路径总和(简单) 题目:给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果…

【QT Creator】基本使用

一、常见问题 解答可见以下链接: https://www.cnblogs.com/xia-weiwen/p/10074882.html#title3.1 ** 有关控制台选择构建套件缺失的解决方法可见以下链接 https://blog.csdn.net/xuxu_123_/article/details/131257928 二、如何创建第一个QT项目 第一步&#xf…

一文解答Swin Transformer + 代码【详解】

文章目录 1、Swin Transformer的介绍1.1 Swin Transformer解决图像问题的挑战1.2 Swin Transformer解决图像问题的方法 2、Swin Transformer的具体过程2.1 Patch Partition 和 Linear Embedding2.2 W-MSA、SW-MSA2.3 Swin Transformer代码解析2.3.1 代码解释 2.4 W-MSA和SW-MSA…

Elasticsearch入门安装

1、下载安装 (1)安装Elasticsearch 下载地址:https://www.elastic.co/cn/downloads/elasticsearch 解压后运行 /bin/elasticsearch.bat 运行后访问 http://127.0.0.1:9200/即可 ps1:若无法访问且控制台打印 received plaintex…