链表中环的入口结点 快慢指针法证明

这篇博客详细介绍了如何使用快慢指针法找到链表中环的入口结点,确保空间复杂度为O(1)和时间复杂度为O(n)。算法首先通过两个指针,一个每次移动一步,一个每次移动两步,寻找环的存在。一旦找到环,快指针回溯到头节点,再次同步移动直至相遇,相遇点即为环的入口。此外,文章还对比了使用hash法的不足之处。
摘要由CSDN通过智能技术生成

链表中环的入口结点 快慢指针法证明

题目

给一个长度为n链表,若其中包含环,请找出该链表的环的入口结点,否则,返回null。

数据范围: n <= 1000001 <= node.val <= 10000

要求:空间复杂度 O(1),时间复杂度 O(n)。

例如,输入{1,2},{3,4,5}时,对应的环形链表如下图所示:

img

可以看到环的入口结点的结点值为3,所以返回结点值为3的结点。

输入描述:

输入分为2段,第一段是入环前的链表部分,第二段是链表环的部分,后台会根据第二段是否为空将这两段组装成一个无环或者有环单链表

输出描述:

返回链表的环的入口结点即可,我们后台程序会打印这个结点对应的结点值;若没有,则返回对应编程语言的空结点即可。

算法描述

1)定义两个指针均指向头节点,分别为快慢指针;

2)两个指针同时遍历链表,慢指针逐个遍历,快指针隔一个遍历;

3)如任何一个指针指向空节点,则返回空节点;

4)否则回到2),重复2)至4),直到快慢指针指向同一节点;

5)将快指针拨回至头节点;

6)两个指针继续同时遍历链表,均逐个遍历;

7)直到快慢指针指向同一节点,返回指向的节点,此节点即为环的入口。

算法原理

可以将这道题目抽象为一种特殊的追及问题,如图所示,h为起点、e为环的入口、p为两个指针出发后第一次相遇的地方,L1、L2分别为非环区域的长度和环状区域的长度,S1、S2分别为相遇之前慢、快指针运动的长度,m为相遇时e与p的距离,其中长度、距离是节点数量的抽象表达。题目要求环的入口结点,抽象后就是求e点的位置,即L1的长度。

在这里插入图片描述

因为 快指针速度是慢指针速度的两倍
所以 S2 = 2 * S1
依题意与图示易得:
	S1 = L1 + m
    S2 = L1 + L2 + m
所以 S2 - L1 = S1 = L2
p距下一次到e还有:
    Xpe = L2 - m
因为 S1 = L2, L1 + m = L2
所以 Xpe = L2 - m = L1
所以 此时将快指针放回h慢速运动,可以使两指针再e相遇

此算法只占用了快慢指针的额外内存空间,与输入规模无关,空间复杂度为O(1)。以慢指针为参照,慢指针走了L1 + L2 = n个节点,由于两指针是同步运动的,无需考虑另一指针,时间复杂度为O(n),符合题目要求。

代码实现

# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def EntryNodeOfLoop(self, pHead):
        fast = pHead
        slow = pHead
        while True:
            if fast.next is None or fast.next.next is None:
                return None
            slow = slow.next
            fast = fast.next.next
            if fast == slow:
                break
        if slow == pHead:
            return pHead
        fast = pHead
        while True:
            fast = fast.next
            slow = slow.next
            if fast == slow:
                return slow

hash法与代码实现

此题中使用hash法有暴力法之嫌,并不高效。遍历节点,将节点hash存储,利用了节点和hash的唯一性,如节点第一次出现第二次,则说明此节点为环的入口。遍历节点造成的时间复杂度如双指针法,为O(n),但每一个节点都需要存储hash会带来额外的内存消耗,空间复杂度为O(n),不符合题目要求。

class Solution:
    def EntryNodeOfLoop(self, pHead):
        nodes = set()
        node = pHead
        while True :
            if node is None:
                return node
            if node.val in nodes:
                return node
            nodes.add(x)
            node = node.next
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值