142 环形链表 ||
题目142 环形链表
思路
主要考察两个点:一个判断是否有环,二是找到环的入口
一、判断链表是否有环
可以使用快慢指针法,分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。
为什么fast 走两个节点,slow走一个节点,有环的话,一定会在环内相遇呢,而不是永远的错开呢?
因为fast是走两步,slow是走一步,其实相对于slow来说,fast是一个节点一个节点的靠近slow的,所以fast一定可以和slow重合。
二:如果有环,如何找到这个环的入口
slow指针到相遇点时的路径:x+y+k(y+z)
fast指针到相遇点时的路径:x+y+n(y+z)
从而可以得到等式:2(x+y)=x+y+n(y+z),x=(n-1)(y+z)+z
证明:k=0,即一定在慢指针进入环后的第一圈就相遇到了,画个直线图就很明确了。另外,n≥1。
当n=1时,可以从等式得到x+z,
那么 n如果大于1是什么情况呢,就是fast指针在环形转n圈之后才遇到 slow指针。
其实这种情况和n为1的时候效果是一样的,一样可以通过这个方法找到 环形的入口节点,只不过,index1 指针在环里 多转了(n-1)圈,然后再遇到index2,相遇点依然是环形的入口节点。
代码
# 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:
slow = head
fast = head
while fast != None and fast.next != None and fast.next.next != None: # 因为快指针移动两步,确保快指针指向不为空即可,若为空了,则无环无相遇点
slow = slow.next
fast = fast.next.next
if slow == fast: # 如果到了相遇的点
index_1 = head
index_2 = slow
while index_1 != index_2: # 找相遇点
index_1 = index_1.next
index_2 = index_2.next
return index_1
return None