题目:
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。
python3代码解答:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
# 首先将两个指针分别放在链表的头部
slow = head
fast = head
# 检查fast指针是否不为None和检查fast指针的下一个节点是否存在,即fast.next是否不为None
while fast and fast.next:
# slow每次移动一步,fast每次移动两步
slow = slow.next
fast = fast.next.next
# 如果链表中存在环,由于fast移动的更快,它最终会从后面追上slow,并且相遇
if slow == fast:
# 一旦fast和slow进行相遇,就把slow设置为链表的头部
# 接着slow和fast都以相同的速度移动(每次一步),他们再次相遇的点,就是环的起始节点
slow = head
while slow != fast:
slow = slow.next
fast = fast.next
# 当fast和slow再次相遇就是环的起始节点,此时可以返回任意一个指针指向的节点,就是起始节点
return slow
# 如果链表没有环,则fast会首先到达链表的表尾(fast或者fast.next会变成None)
return None
上述代码解析:
上述代码是用来在链表中检测环的存在,并且找到这个环的起始节点。使用“快慢指针”(Floyd的乌龟和兔子算法)的技术。核心思想是使用两个指针以不同的速度移动:一个快指针(每次移动两步)和一个慢指针(每次移动一步)。如果链表中存在环,那么快指针最终会从后面追上慢指针。具体解释如下:
-
起点设置:首先,将两个指针都放在链表的头部,这两个指针分别是
slow
(慢指针)和fast
(快指针)。 -
开始追逐:在链表上移动这两个指针,
slow
每次移动一步,而fast
每次移动两步。这一过程会持续进行,直到fast
到达链表的末尾或者fast
追上slow
(即slow == fast
)。 -
检测到环:如果链表中存在环,由于
fast
移动得更快,它最终会从后面追上slow
,这时两者的位置相同。 -
找到环的起点:一旦
slow
和fast
相遇,就将slow
重新设置到链表的头部,但这次两者都以相同的速度移动(每次一步)。他们再次相遇的点,就是环的起始节点。 -
返回环的起始节点:当
slow
和fast
再次相遇时,就在环的起始节点相遇。此时,返回任意一个指针指向的节点,这个节点就是环的起始点。 -
如果没有环:如果链表中没有环,那么
fast
会首先到达链表的末尾(fast
或fast.next
会变成None
)。这时,函数返回None
,表示链表中没有环。
该题的算法能够有效地在链表中检测环的存在,并找到环的入口点,好处是不需要额外的存储空间(比如使用一个集合来存储访问过的节点),所以它的空间复杂度为O(1),而时间复杂度保持为O(n),其中n是链表中的节点数。
注:其实不理解为什么在相遇之后,要把慢节点返回成头指针然后再以相同的速率去移动快慢指针,我们在自己计算的时候,就可以画类似这样的图,先判断在什么时候相遇,接着把慢指针指向头结点,最后在依次移动快慢指针,当他们再次相遇的时候,正好是下图所示的SB和fB点。(其中我以第一次移动的时候slow和fast写为123等。第二次移动写成AB等,表示的共同移动的步骤)
本文的对于力扣142.环形链表II的python3解答,仅仅是个人学习资料记录,也十分高兴我的见解可以帮助其他的正在做这个题目的同学,基础较差,仅仅是个人见解,大神勿喷,欢迎交流,谢谢!