Leetcode第142题:环形链表 II

leetcode 142题——环形链表 II,自己先写了一遍,发现和《代码随想录》代码差不多,但感觉《代码随想录》解释讲的还是很绕,所以将自己的推导写一下,方便大家理解。首先该题需先判断是否有闭环,然后再查找环的入口,示意图如下:


(该图引用自代码随想录

1. 判断闭环

采用快慢指针,快指针一次走两步,慢指针一次走一步,则若有闭环,一定会在闭环中相遇,原因如下:

假设头结点到环入口长度为 x x x,环入口到相遇点长度为 y y y,相遇点到环入口长度为 z z z,假设相遇时间为 t ( t ≥ x ) t(t\ge x) t(tx),则 slow  \text{slow } slow 走了 t t t 个结点, fast  \text{fast } fast 走了 2 t 2t 2t 个结点,而环的周期为 y + z y+z y+z,则根据关系式有
t + k ( y + z ) = 2 t t = k ( y + z ) \begin{aligned} t+k(y+z)&=2t\\ t&=k(y+z) \end{aligned} t+k(y+z)t=2t=k(y+z)
其中 k k k fast  \text{fast } fast  slow  \text{slow } slow 多走的圈数,显而易见 k ≥ 1 k\ge1 k1,则当 k k k 1 1 1 时, t t t 取得最小值为 y + z y+z y+z,而
x ≤ t min = y + z ≤ x + y + z x\le t_{\text{min}}=y+z\le x+y+z xtmin=y+zx+y+z
即第一次相遇时, slow  \text{slow } slow 至多走完一圈(取决于 x x x 是否为0)。因此 slow  \text{slow } slow  fast  \text{fast } fast 指针必定会相遇,且 slow  \text{slow } slow 指针此时还在第一圈, fast  \text{fast } fast 指针已经到第二圈。

2. 查找环入口

所以程序在实现时,优先判断有没有环,若存在环,则此时 slow 走过的节点数为 y + z y+z y+z 个。而 slow 实际走过的节点数为 x + y x+y x+y 个,因此根据关系式有
y + z = x + y x = z \begin{aligned} y+z&=x+y\\ x&=z \end{aligned} y+zx=x+y=z
即当前 slow  \text{slow } slow 指针到达环入口和从 head  \text{head } head 到达环入口的节点个数相同,那么此时想要查找环入口只需要将 fast  \text{fast } fast  指针指向 head  \text{head } head  节点,然后两个指针一起按一步移动,再次相遇处即环入口。
复杂度分析:由于 slow  \text{slow } slow  fast  \text{fast } fast 只取第一次相遇,走过两次链表+ x x x个节点长度,因此复杂度为 O ( N ) O(N) O(N)

代码
# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def detectCycle(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        # dummy_node = ListNode(0)
        # dummy_node.next = head

        slow, fast = head, head     # 快慢指针指向头结点

        while fast and fast.next:   
            slow = slow.next        # 慢指针走一步
            fast = fast.next.next       # 快指针走两步

            if slow == fast:        # 两指针相遇
                fast = head     # 将快指针指向头结点

                while slow != fast:     # fast和slow一起以一步走,再次相遇处即环入口处
                    slow = slow.next
                    fast = fast.next

                return slow

        return None
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值