当前位置: 首页 > article >正文

【单链表算法实战】解锁数据结构核心谜题——环形链表

题目如下:

在这里插入图片描述

解题过程如下:

环形链表:尾结点的next指针不为空,而是指向链表中的任一结点。
在这里插入图片描述
思路:快慢指针,慢指针每次走一步,快指针每次走两步。快慢指针在环中追逐相遇,那么这个链表为环形链表;快慢指针没有相遇,那么这个链表不是环形链表。

在这里插入图片描述

完整代码如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
typedef struct ListNode ListNode;
bool hasCycle(struct ListNode *head) {
    //快慢指针,相遇为环形链表,否则不是环形链表
    ListNode* slow = head;
    ListNode* fast = head;
    while (fast && fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
        if (slow == fast)
        {
            return true;
        }
    }
    return false;
}

试着证明:

  1. 在环形链表中,快慢指针,慢指针每次走1步,快指针每次走2步,在环中追逐一定会相遇。

具体示例画图分析,slow和fast之间的距离变化:1 2 3 2 1 0,3是这里的最大距离。但是,在面试中被问到如何求证,可不能画一个具体例子说明,这就不是证明了!
在这里插入图片描述

slow和fast入环之后,分析追逐的过程中距离的变化,既然一定会存在最大距离,那么假设此时slow刚入环,slow和fast的最大距离为N,之后每追击1次,距离会缩小1步:
在这里插入图片描述
在这里插入图片描述
最终slow和fast的距离为0,说明一定会相遇。

  1. 在环形链表中,快慢指针,慢指针每次走1步,快指针每次走3/4/5……步,在环中追逐一定会相遇吗?
    在这里插入图片描述
    在环形链表中,慢指针每次走1步,快指针每次走3步,假设此时slow刚入环,slow和fast的最大距离为N,之后每追击1次,距离会缩小2步,在环中追逐的过程中距离的变化:
    在这里插入图片描述
    N为奇数时,下一圈会相遇吗?N为奇数时,下一圈追逐:
    当C - 1为偶数时,即C为奇数,一定会相遇;
    当C - 1为奇数时,即C为偶数,一定不会相遇。

在这里插入图片描述

上图为例,慢指针每次走1步,快指针每次走3步,快慢指针走过的路程之间的关系:3 * 慢指针 = 快指针

假设:入环结点到头结点的距离是L,此时slow刚刚入环,fast已经在环内绕了n圈。

快慢指针走的路程分别为:
慢指针:L
快指针:L + C - N + nC

根据公式3 * 慢指针 = 快指针2L = (n + 1)C - N
先分析2L:由于偶数 * 偶数 = 偶数;偶数 * 奇数 = 偶数,所以2L一定是偶数。
已知N为奇数,由于偶数 = 偶数 - 偶数;偶数 = 奇数 - 奇数,所以(n + 1)C一定是奇数,若当中C为偶数,那么(n + 1)C也为偶数,与结论(n + 1)C一定是奇数相悖,所以C一定是奇数。

由于:

N为奇数时,下一圈会相遇吗?N为奇数时,下一圈追逐:
当C - 1为偶数时,即C为奇数,一定会相遇;
当C - 1为奇数时,即C为偶数,一定不会相遇。

综上,在环形链表中,慢指针每次走1步,快指针每次走3步,快慢指针在环中追逐一定会相遇。同理,慢指针每次走1步,快指针每次走4/5/……步,快慢指针在环中追逐也一定会相遇,证明过程同上。

慢指针每次走1步,快指针每次走3步,完整代码如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
typedef struct ListNode ListNode;
bool hasCycle(struct ListNode *head) {
    //快慢指针,慢指针每次走1步,快指针每次走3步
    ListNode* slow = head;
    ListNode* fast = head;
    while (fast && fast->next)
    {
        slow = slow->next;
        int n = 3;
        while (n--)
        {
            if (fast->next)
            {
                fast = fast->next;
            }
            else{
                return false;
            }
        }
        if (slow == fast)
            {
                return true;
            }
    }
    return false;
}

虽然已经证明了快指针在环中无论走多少步都会与慢指针相遇,但是这会在算法题中增加额外的代码。所以,涉及到快慢指针的算法题通常会习惯使用慢指针走1步,快指针走2步的方法。


http://www.kler.cn/a/522314.html

相关文章:

  • Solon Cloud Gateway 开发:Route 的过滤器与定制
  • java基础-容器
  • 初始JavaEE篇 —— Spring Web MVC入门(上)
  • 通过protoc工具生成proto的pb.go文件以及使用protoc-go-inject-tag工具注入自定义标签
  • Linux常见问题解决方法--1
  • RAG是否被取代(缓存增强生成-CAG)吗?
  • 基于PostgreSQL的自然语义解析电子病历编程实践与探索(下)
  • vim多文件操作如何同屏开多个文件
  • 软件测试丨Airtest 游戏自动化测试框架
  • 电梯系统的UML文档12
  • LangChain:使用表达式语言优化提示词链
  • 论文阅读(三):微阵列数据的图形模型和多变量分析
  • UF_CAM常用函数
  • C++ - AVL平衡二叉树
  • 一. 初始 Redis(快速入门-00)
  • KMP算法原理 JAVA实现
  • 缓存穿透和缓存雪崩
  • C#/.NET/.NET Core技术前沿周刊 | 第 23 期(2025年1.20-1.26)
  • deepseek-r1技术报告解析
  • 在RHEL 8.10上安装开源工业物联网解决方案Thingsboard 3.9
  • 【Linux】互斥锁、基于阻塞队列、环形队列的生产消费模型、单例线程池
  • “基因合作:生命演化中的共生与目的性”
  • 【2024年华为OD机试】 (A卷,200分)- 开放日活动、取出尽量少的球(JavaScriptJava PythonC/C++)
  • 6. 使用springboot做一个音乐播放器软件项目【1.0版项目完结】附带源码~
  • Android SystemUI——最近任务列表启动(十八)
  • FPGA 26,数码管动态显示,解析与实现( 使用 Xilinx Vivado 实现数码管动态显示 )