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

ops/2025/2/2 15:08:07/

题目如下:

在这里插入图片描述

解题过程如下:

环形链表:尾结点的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.ppmy.cn/ops/155059.html

相关文章

FastAPI + GraphQL + SQLAlchemy 实现博客系统

本文将详细介绍如何使用 FastAPI、GraphQL(Strawberry)和 SQLAlchemy 实现一个带有认证功能的博客系统。 技术栈 FastAPI:高性能的 Python Web 框架Strawberry:Python GraphQL 库SQLAlchemy:Python ORM 框架JWT&…

算法基础学习——快排与归并(附带java模版)

快速排序和归并排序是两种速度较快的排序方式,是最应该掌握的两种排序算法, (一)快速排序(不稳定的) 基本思想:分治 平均时间复杂度:O(nlogn) / 最慢O(n^2) / 最快O(n) 步骤&…

亚博microros小车-原生ubuntu支持系列:17 gmapping

前置依赖 先看下亚博官网的介绍 Gmapping简介 gmapping只适用于单帧二维激光点数小于1440的点,如果单帧激光点数大于1440,那么就会出【[mapping-4] process has died】 这样的问题。 Gmapping是基于滤波SLAM框架的常用开源SLAM算法。 Gmapping基于RBp…

【13】WLC HA介绍和配置

1.概述 本文对AireOS WLC的HA进行介绍,和大多数网络架构设计一样,单台的WLC是无法保证设备的冗余性的,而且WLC也不是双引擎的设备,所以需要依靠High Available的技术来为WLC提供高可用性。 2.WLC HA类型 AireOS WLC的高可用性技术可以分为N+1的SSO的HA。不是所有的设备都…

论文阅读(十):用可分解图模型模拟连锁不平衡

1.论文链接:Modeling Linkage Disequilibrium with Decomposable Graphical Models 摘要: 本章介绍了使用可分解的图形模型(DGMs)表示遗传数据,或连锁不平衡(LD),各种下游应用程序之…

C#,入门教程(11)——枚举(Enum)的基础知识和高级应用

上一篇: C#,入门教程(10)——常量、变量与命名规则的基础知识https://blog.csdn.net/beijinghorn/article/details/123913570 不会枚举,就不会编程! 枚举 一个有组织的常量系列 比如:一个星期每一天的名字&#xf…

论文阅读(十三):复杂表型关联的贝叶斯、基于系统的多层次分析:从解释到决策

1.论文链接:Bayesian, Systems-based, Multilevel Analysis of Associations for Complex Phenotypes: from Interpretation to Decision 摘要: 遗传关联研究(GAS)报告的结果相对稀缺,促使许多研究方向。尽管关联概念…

python recv的概念和使用案例

recv 是网络编程中用于从套接字接收数据的核心函数,常见于 TCP/UDP 通信。以下是其概念、用法和案例详解: 概念 作用:从已连接(TCP)或已绑定(UDP)的套接字接收数据。参数: bufsize:…