代码随想录刷题-链表-环形链表II
创始人
2025-05-30 11:27:46
0

文章目录

    • 环形链表 II
      • 习题
      • 我的解法
      • 双指针

环形链表 II

本节对应代码随想录中:代码随想录,讲解视频:把环形链表讲清楚! 如何判断环形链表?如何找到环形链表的入口? LeetCode:142.环形链表II_哔哩哔哩_bilibili

习题

题目链接:142. 环形链表 II - 力扣(LeetCode)

给定一个链表的头节点 head ,返回链表开始入环的第一个节点。如果链表无环,则返回 null。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改链表。

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。

进阶:你是否可以使用 O(1) 空间解决此题?

我的解法

非最优解,只是个人解法记录

我的想法是遍历每个节点,并且用 now 记录虚拟头节点到当前节点的距离,同时用 last 记录上一个 now 值。对于每个节点从头节点向后遍历,比较 now 和 last。

当出现环的时候,比如上图的3 2 0 -4,cur 指向-4时,虚拟头结点到-4的距离为4,当遍历下一个节点即2时,虚拟头结点到2的距离仅为2。也就是从虚拟头节点到当前节点的距离比到下一个节点的距离还短的时候,那说明肯定出现了环,并且当前节点即-4是环的"最右"节点,而下一个节点即2是环的入口。也即是 now,而如果节点的下一个节点是自身,那就是 now=last,所以判断条件就是 now<=last

class Solution {public:ListNode* detectCycle(ListNode* head) {ListNode* dummyHead = new ListNode(0,head);ListNode* cur = head;int now = 0,last = 0;   // now记录从虚拟头节点到当前结点的距离,last保存上一个now的值while(cur!=nullptr){ListNode* tmp = dummyHead;now = 0;while(tmp!=cur){tmp = tmp->next;now++;}// 核心语句:当last值小于等于now值说明cur是环的起点if(now <= last){return cur;}last = now; // last保存上一个now值cur = cur->next;}return nullptr;}
};
  • 时间复杂度:O(n^2)。这段代码的核心是两个嵌套的 while 循环,外层循环遍历链表中的每个节点,内层循环遍历链表中从虚拟头节点到当前节点的距离。因此,总的时间复杂度为 O(n^2)。
  • 空间复杂度:O(1)。这段代码只使用了常数级别的额外空间,即定义了几个指针和两个整型变量,因此空间复杂度为 O(1)。

但这种解法的时间复杂度为 O(n^2),并非最优解,如果用哈希表来判断是否出现重复也只需要 O(n)。但由于只是想记录下自己的解法,所以也写出来了,算是拓展途径。由于代码随想录中的哈希表在后面章节,并且此题哈希表也不是最优解,因此这里就不放哈希表的解法了。

双指针

1.怎么确定是否有环?

使用两个指针 fast 和 slow,fast 指针每次走两步,slow 指针每次走一步。如果有环,那么它们一定会在环内某处相遇。

原因:如果有环,那么两个指针一定最后是在环内一直转圈,而由于 fast 指针每次都比慢指针多走一步。可以理解成快指针每次都和慢指针的距离缩小1步,那么他们之间的距离最终一定会缩减为0即相遇。

2.确定有环后怎么确定环的入口?

这里就要用到数学推导了。如下图,a 为头结点到环入口的距离,b 为环入口到相遇点(紫色)的距离,c 为相遇点到环入口的距离。那么 fast 指针走的距离 Sf = a+n(b+c)+b,而 slow 指针走的距离为 Ss=a+b,那么就有

Sf=2Ss即 a+n(b+c)+b = 2(a+b)即 a=c+(n-1)(b+c)

也就是从头节点到环入口的距离刚好等于 n-1圈的环加上 c 的距离,也就是说当快慢指针相遇时,我们可以再定义一个指针起始点为头节点,每次和 slow 指针一样也是走一步,那么根据上面的式子他们一定会在环的入口相遇。

class Solution {
public:ListNode *detectCycle(ListNode *head) {ListNode* fast = head;ListNode* slow = head;// 链表为空或者只有一个节点且无环时直接返回nullptrwhile(fast != nullptr && fast->next != nullptr) {// 慢指针走一步,快指针走两步slow = slow->next;fast = fast->next->next;// 快慢指针相遇,此时从head和相遇点,同时移动直至相遇if (slow == fast) {ListNode* ptr = head;while (ptr != slow) {ptr = ptr->next;slow = slow->next;}return ptr; // 返回环的入口}}return nullptr;}
};
  • 时间复杂度:O(n)。其中 n 为链表中节点的数目。在最初判断快慢指针是否相遇时,slow 指针走过的距离不会超过链表的总长度;随后寻找入环点时,走过的距离也不会超过链表的总长度。因此,总的执行时间为 O(n)+O(n)=O(n)。
  • 空间复杂度:O(1)。我们只使用了 slow,last 和 ptr 三个指针。

相关内容

热门资讯

美国加州州长:美国政府“违法”... 美国加利福尼亚州州长加文·纽森在5月30日播出的一档节目中批评联邦政府“单边”且“非法”的关税政策,...
第一个 Django 应用 1. 创建项目 1.1 新建项目 首先新建一个项目,名为 mysite,...
经典卷积模型回顾32—利用YO... YOLOv3(You Only Look Once version 3,...
70. 爬楼梯 70. 爬楼梯 总结 easy题。 题目形成的数列正好是斐波那契数列,答案要求的f(...
端午节假期,石家庄市动物园免票... 端午节撞上儿童节,去哪遛娃儿?别着急,近日,石家庄市动物园依托自有文创品牌“石动萌主”,精心策划并推...
上海警方通报共享单车坐垫内有情... 央广网上海5月31日消息(记者郑晓蔚 见习记者何智康)近日,上海一网友称,哈啰共享单车坐垫内有成人情...
【操作系统复习】第2章(Par... 第2章(Part II)进程的描述与控制冯诺依曼体系结构:...
Web前端学习:章四 -- J... 106:for循环深入 1、标准格式: for(初始化条件;判断条件;迭...
精神病人扰民困境:自由与安全的... 2025 年 5 月,吉林松原的刁先生向荔枝新闻讲述了自家长达两年多的困扰。自 2022 年 12 ...
关于glibc的若干问题总结 今天在学习C的库函数memchr时,想看看其实现的源码,所以去网上下载了...