给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:tail connects to node index 0
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:no cycle
解释:链表中没有环。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/linked-list-cycle-ii
方法一:利用集合(set)的无序的不重复元素序列的特性。把visited的节点存在set里,延用环形链表 I的做法
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
if not head or not head.next:
return None
visited = set()
while(head):
if head in visited:
return head
else:
visited.add(head)
head = head.next
return None
方法二:快慢指针。参考LeetCode官方解答
链接:https://leetcode-cn.com/problems/linked-list-cycle-ii/solution/huan-xing-lian-biao-ii-by-leetcode/
阶段一:如果是环形链表,慢指针一次走一步,快指针一次走两步,快慢指针总会在环中某一节点相遇。可以想象,在一个环里跑,跑得快的总能追上跑得慢的。因此快慢指针相遇则证明是环形链表。
阶段二:在第一次相遇后,慢指针仍指向相遇位置,快指针指向起点位置。快指针变为只走一步,快慢指针的第二次相遇总是在入口节点处。(这个规律挺难想到的,下面做证明)
图片来源于 LeetCode官方解答
F为起点到环入口的距离,h为快慢指针相遇的位置。环入口与h把环分为a与b两个部分。
当环很大时,a+b>F的情况:
快慢指针在h点相遇,慢指针走了F+a,快指针比它多走一个环,走了F+a+b+a。因为慢指针走的距离是快指针的一半,2(F+a)=F+2a+b,所以F=b。即多走的环a+b=F+a, b=F 。即快指针在起始位置以步长1走F,慢指针在h位置,以步长1走 b,它们会在入口位置相遇。
当环很小,F距离很长的情况:
环小的话,可能快指针多走n个环。2(F+a)=F+a+n(a+b),F=(n-1)(a+b)+b.
一个走F的距离,一个绕很多圈因为+b还是会走到入口和另一个相遇。
评论里的一个证明:
来源于@振之 https://leetcode-cn.com/u/zhen-zhi/,他分析的是当环很大时,a+b>F的情况。
图一:当慢指针slow走n走到环入口时,快指针fast走2n走到当前位置。
图二:当慢指针走n+b走到当前位置时,当前位置距离环入口n。此时快指针走2(n+b),跟慢指针相遇。让快指针回到起始节点,同走n步就能在环入口相遇。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
if not head or not head.next:
return None
slow = fast = head
while(fast.next.next and slow.next):
fast = fast.next.next
slow = slow.next
if not fast.next or not slow.next:
return None
if fast == slow:
cur = slow
pre = head
while(cur!=pre):
cur = cur.next
pre = pre.next
return cur
return None
来源:CSDN
作者:一小坨北北
链接:https://blog.csdn.net/weixin_39331401/article/details/104607755