142 环形链表 ||

题目142 环形链表

思路

主要考察两个点:一个判断是否有环,二是找到环的入口
一、判断链表是否有环
可以使用快慢指针法,分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。

为什么fast 走两个节点,slow走一个节点,有环的话,一定会在环内相遇呢,而不是永远的错开呢?
因为fast是走两步,slow是走一步,其实相对于slow来说,fast是一个节点一个节点的靠近slow的,所以fast一定可以和slow重合。

二:如果有环,如何找到这个环的入口
image
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
posted @ 2022-09-02 11:00  时光如你般美好  阅读(31)  评论(0编辑  收藏  举报