leetcode刷题:Linked List Cycle II (链表循环 II) 详解

原题

题目链接
Given a linked list, return the node where the cycle begins. If there is no cycle, return null.

To represent a cycle in the given linked list, we use an integer pos which represents the position (0-indexed) in the linked list where tail connects to. If pos is -1, then there is no cycle in the linked list.

Note: Do not modify the linked list.

Example 1:

Input: head = [3,2,0,-4], pos = 1
Output: tail connects to node index 1
Explanation: There is a cycle in the linked list, where tail connects to the second node.

在这里插入图片描述
例子只列一个,这题的介绍把我弄的有点晕,总之就是写一个函数,函数会接收一个Linkedlist,判断这个Linkedlist中有没有环,并反悔环起始的node,上例中对应的就是2这个节点(吐槽一下Example没有很好的介绍清楚函数的输入和输出,搞得我疑惑了两分钟)
我看了讨论区的几个讨论解释的都不是很清楚,所以这篇我会解释详细一点。

总结

在这题中,我们要解决两个问题:

  • LinkedList中是否包含环
  • 如果包含环,环的起点在哪里

这里,我只讨论空间复杂度为O(1)的解法,不考虑空间复杂度用一个Set就可以很容易得到答案。
第一步:解决第一个问题,我们可以从Linked List Cycle I找到答案,这里我直接说方案: 使用两个指针,一个slow每次前进一步,一个fast每次前进两部。如果在前进的过程中slow和fast重合,那么就说明他们有环。

第二步:当我们断定有环的时候,如何得到环的入口位置。
假设如下情况
在这里插入图片描述
图中点的含义:
S:链表的起点
L:循环的起点
M:相遇的点
定义如下距离
x1 : S到L
x2 : L到M
x3 : M到L

那么有slow此时步长:x1 + r(x2 + x3) + x2 ; fast此时步长:x1 + n(x2 + x3) + x2, 其中r为slow绕圈的次数,n为fast绕圈的次数
根据 2 * slow = fast有:
2x1 + r(x2 + x3) + 2x2 = x1 + n(x2 + x3) + x2
化简:x1 = (n - r - 1) (x2 + x3) + x3
上式说明,一个点从M开始走x1步,会到达L。也就说说我们可以设置两个指针从S,M开始,每次都一步,当两个指针相等时,就会落在L点

代码:

# 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
        """
        slow = fast = head
        
        while True:
            if fast and fast.next:
                fast = fast.next.next
            else:
                return None
            
            slow = slow.next
            if fast == slow:
                break
             
        p1 = head
        p2 = slow
        while p1 != p2:
            p1 = p1.next
            p2 = p2.next
            
        return p1

简单分析一下复杂度
分两种情况:

  1. slow到L点时刚好和fast相遇
    在N内相遇。
  2. slow和fast相遇在环的起点之后
    在这种情况下,slow遍历会在到达N之前结束
    在这里插入图片描述
    L-N的长度设为K, 假设slow第一次到达L,因为slow和fast此时没有相遇,可以断定fast一定在(L,N]的区间。此时fast于slow的距离必然小于等于N-L,fast和slow的步差为1,那么在N-L步之内,slow和fast必然相遇。假设最大再走N-L步,slow最多也只能达到N。

可以看出算法可以在 2N时间内完成(N为List长度),故时间复杂度O(N)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值