环形链表Ⅱ
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。
思路:
这一题在环形链表的基础上加了一个要求:找到开始入环的第一个节点。方法还是先按快慢指针的思路判断是否有环,如果有环再进一步去找入环的那个节点。
但怎么找到入环的节点呢?其实非常简单,就是一个脑筋急转弯问题而已,直接说结论:当我们找到了快慢指针在环内的相遇处时,将其中一个指针挪到开头,另一个依然保留在相遇处,此时两者按同速度前进,再相遇处就是入环点。
这是为什么呢?画一个图就很明白了(虽然画的很丑):
现在有一个带环链表,当快慢指针相遇是,如果慢指针一共走了n步,则快指针必然走了2n步,此时快指针走的路减去慢指针走的路,正好是一个环,长度为n——所以这也是一个结论:相遇时慢指针走了多远,链表里的环就多长。现在假设入环处与相遇点距离为l,则从相遇点再走n-l步就可以到达入环处;而从头节点开始走,本来走n步到达相遇点,同样是走n-l步到达入环处。因此一个指针在头结点,另一个指针在相遇点,两者同时同速走,必然各自走完n-l的距离后能正好相会于入环处。
代码:
class Solution(object):
def detectCycle(self, head):
left=head
right=head
flag=0#标记,判断是否有环用的,初始为0无环
while(right and right.next):#判断快指针是否到头
left=left.next#慢指针走一步
right=right.next.next#快指针走两步
if left==right:#如果相遇,证明有环
flag=1#标记flag为1
break#马上跳出,此时left和right都在相遇处
if not flag:#如果没有环,返回None
return None
elif flag:#如果有环
left=head#一个回到头,另一个在交界处不变(right)
#同时前进 相遇位置即环入口
while(left!=right):#同速进行直到相遇
left=left.next
right=right.next
return left#相遇处就是入环处,返回right也一样
小结:
这个题只要在用快慢指针判断环形链表的基础上再额外记住一个找到入环处的“小结论”就好了,这也是容易并且一定要掌握的。可以看出对于这一类题只要知道了快慢指针,不管是原题还是变式也都是信手拈来~
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了