Leetcode 142. 环形链表 II

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 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

解释:链表中没有环。

 

进阶:

你是否可以不用额外空间解决此题?

**难度**: Medium

**标签**: 链表、 双指针、


# -*- coding: utf-8 -*-
# @Author  : LG

"""
执行用时:52 ms, 在所有 Python3 提交中击败了98.32% 的用户
内存消耗:16.3 MB, 在所有 Python3 提交中击败了74.63% 的用户

解题思路:
    快慢指针

    |<----    l1   ---->|< --------
    1   2   3   4   5   6   7   8   l2
                        15      9   ↓
                        14      10  __
                        13  12  11

    从头部到入环 距离为 l1, 入环到快慢指针相遇点为l2, 环长 c

    则, 慢指针走过的距离为 s = 1 + l1 + l2
        快指针走过的距离为 f = l1 + l2 + nc  绕了环内走了n圈

    2s = f
    则,  2 + 2l1 + 2l2 = l1 + l2 + nc

    所求入环处 l1 = nc - l2 - 2
    nc - l2 可由 慢指针从相遇处 开始绕环走到入环处得来。
    即 在相遇时,从起点前两个距离开始,初始化一个指针, 同时慢指针从相遇处继续走。 新指针与慢指针会在入环处相遇
"""
class Solution:
    def detectCycle(self, head: ListNode) -> ListNode:
        s, f = ListNode(0, next= head), head    # 快慢指针

        while s != f:   # 相遇则有环,且当前位置为相遇处
            if f and f.next:
                s = s.next
                f = f.next.next
            else:   # 无环
                return
        # 有环时,初始化一个新指针,在开始前两个距离处
        new = ListNode(0, next=ListNode(0, next = head))    # 新指针

        while new != s: # 新指针与慢指针同时走,相遇处便是入环点
            new = new.next
            s = s.next

        return s