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

LeetCode 142.环形链表 II

目录

  • 1 题目概述
  • 2 题目解法
  • 3 证明

原题链接

环形链表 II

前言
在做这道题目之前,应该先做一次 环形链表 I 和 相交链表,这样对这道题目中所使用的方法会有较深的理解

1 题目概述

给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 不允许修改链表。

示例1:
在这里插入图片描述
使用指针来遍历这个链表的时候,指针会不断地在 2,0,-4 三个结点处打转,这就说明链表内是有环的,而我们要做的事情,就是返回环的第一个结点 2

示例2:
在这里插入图片描述

在遍历这个链表时,指针不会在结点中打转,因此它并不存在环,也不存在环的第一个结点,返回空即可

2 题目解法

在解这道题目时,我们需要进行两个操作,判断链表中是否有环找出环内的第一个结点

判断链表中是否有环的办法,与 环形链表 I 一致,采用快慢指针来判断,快指针一次走两步,慢指针一次走一步,当快慢指针相遇,则说明有环。

找出环内的第一个结点则有两种方法,第一种方法是,在快慢指针相遇的位置设定新指针 meet,在链表的头部设定指针 cur,让两个指针同时移动,每次移动一步,当它们相遇时,就可以找到环内的第一个结点。第二种方法则是,当快慢指针相遇时,将它们所指向的下一个结点记录为nextNode,将指向的本结点的 next 指针断开,构造出两个链表,再找两个链表公共部分的第一个结点即可。接下来,对两个方法进行图示说明:

第一种方法
在这里插入图片描述
第二种方法
在这里插入图片描述
在断开并产生两个链表后,先遍历较长链表,使其剩下的长度等于短链表,再同时遍历,直到指针相遇,就可以找到相交的结点

代码如下

//方法1
struct ListNode* detectCycle(struct ListNode* head)
{ListNode* slow = head;ListNode* fast = head;//判断是否有环while (fast && fast->next){slow = slow->next;fast = fast->next->next;if (slow == fast){ListNode* cur = head;ListNode* meet = slow;//找入环第一个结点while (cur != meet){cur = cur->next;meet = meet->next;}return cur;}}return NULL;
}//方法2
ListNode* getCrossNode(ListNode* ListA, ListNode* ListB)
{ListNode* curA = ListA;ListNode* curB = ListB;int lenA = 0;int lenB = 0;while (curA){lenA++;curA = curA->next;}while (curB){lenB++;curB = curB->next;}//假设法int k = abs(lenA - lenB);ListNode* longList = ListA;ListNode* shortList = ListB;if (lenB > lenA){longList = ListB;shortList = ListA;}//部分遍历长链表while (k--){longList = longList->next;}//同时遍历while (shortList != longList){shortList = shortList->next;longList = longList->next;}return shortList;
}struct ListNode* detectCycle(struct ListNode* head)
{ListNode* slow = head;ListNode* fast = head;//判断是否有环while (fast && fast->next){slow = slow->next;fast = fast->next->next;//拆分链表if (slow == fast){ListNode* nextNode = slow->next;slow->next = NULL;return getCrossNode(head, nextNode);}}return NULL;
}

3 证明

为什么让 meet 指针从 slow 和 fast 相遇的位置开始走,让 cur 从头开始走一定能够相遇呢?
假设现在有一个链表,在这个链表中,slow 刚进入环,指向入环的第一个结点,而 fast 已经在环内走了一段距离
在这里插入图片描述
继续移动,直到 fast 和 slow 相遇。在此将链表起始位置到入环第一个结点的距离设为 L,slow 入环后走的距离为 N,环的一圈距离为 C,走过的圈数为 x
在这里插入图片描述

在这个情况下,slow 走的距离为 L + N,fast 走过的距离为 L + x * C + N (x ≠ 0)

x ≠ 0 是因为,fast 的速度是 slow 的两倍,当 slow 和 fast 相遇时,fast 至少走过了一圈

由于 fast 和 slow 走的时间相同,fast 的速度是 slow 的两倍,因此 fast 走过的距离是 slow 的两倍,我们可以得到 2 (L + N) = L + x * C + N

对这个式子进行化简,最终会得到 L = x * C - N

当 x 取 1 时,L = C - N,也就是说明,从相遇的位置开始到入环第一个结点的距离 和 从链表头开始到入环第一个结点的距离是相同的,因此,meet 和 cur 一定会相遇

http://www.dtcms.com/a/357294.html

相关文章:

  • 【前端教程】JavaScript 数组对象遍历与数据展示实战
  • 动态规划01背包
  • 解锁Libvio访问异常:从故障到修复的全攻略
  • 从“Where”到“Where + What”:语义多目标跟踪(SMOT)全面解读
  • C# 日志写入loki
  • 海外广告流量套利:为什么需要使用移动代理IP?
  • 接吻数问题:从球体堆叠到高维空间的数学奥秘
  • 告别K8s部署繁琐!用KubeOperator可视化一键搭建生产级集群
  • 玄机靶场 | 冰蝎3.0-jsp流量分析
  • ACID分别如何实现
  • Dockerfile实现java容器构建及项目重启(公网和内网)
  • SOME/IP-SD IPv4组播的通信参数由谁指定?
  • React学习教程,从入门到精通, ReactJS - 特性:初学者的指南(4)
  • C++链表双杰:list与forward_list
  • ElasticSearch对比Solr
  • Node.js 的流(Stream)是什么?有哪些类型?
  • DQL单表查询相关函数
  • STM32F2/F4系列单片机解密和芯片应用介绍
  • Ubuntu虚拟机磁盘空间扩展指南
  • AI视频安防,为幼儿园安全保驾护航
  • 基于 GPT-OSS 的成人自考口语评测 API 开发全记录
  • 深度解密SWAT模型:遥感快速建模、DEM/LU/气象数据不确定性、子流域/坡度划分、未来土地利用与气候变化情景模拟及措施效益评估
  • 龙巍:探究青铜器在木雕中的运用
  • VS Code C#调试完全指南
  • [AI人脸替换] docs | 环境部署指南 | 用户界面解析
  • 红色视频剪辑制作——走进广州农讲所:在红墙黄瓦间感悟初心与传承
  • “游戏手柄”线性霍尔传感器IC替代方案:赛卓SC470X
  • Instance Normalization(实例归一化)
  • Stage应用模型及状态存储
  • 【Android 16】Android W 的冻结机制内核分析