如何判断链表有环

题目描述:有一个单向链表,链表中有可能出现“环”,如下图,那么,如何用程序来判断该链表是否为有环链表呢?

 

方法一:

       从头节点开始遍历每一个节点,每遍历一个新节点就从头检查到新节点之前的所有节点,如果和该新节点的值有重复,则证明该节点被遍历过两次,链表有环;如果不存在与新节点相同值的节点,就继续遍历下一个新节点,继续重复上述操作。

假设链表的节点数量为n,则该解法时间复杂度为O(^{n^{2}}),由于未创建额外存储空间,空间复杂度为O(1)。

方法二:

       引入哈希表,创建一个以节点ID为key的set集合,用来存储曾经遍历过的节点。然后同样从头遍历单链表中的每一个节点,每遍历一个节点,都用新节点与set集合中存储的节点进行比较,如果发现set中存在与之相同的节点ID,则说明链表有环,如果不存在,就把这个节点ID存入set集合中,继续遍历下一个节点,重复上述操作。

两种方法本质区别是使用了set作为额外的缓存。

假设链表节点数量为n,则该解法的时间复杂度为O(n),由于创建了额外存储空间,空间复杂度为O(n)。

方法三:

       模拟追及问题,首先创建两个指针p1和p2(在Python中就是两个对象引用),让它们同时指向链表的头节点,然后开始循环遍历节点,其中p1每次向后移动1个节点,p2每次向后移动2个节点,然后比较两个指针指向的节点是否相同,如果相同,则可以判断出链表有环,如果不同,则继续下一次循环。

假设链表节点数量为n,则该解法的时间复杂度为O(n),由于未创建额外存储空间,空间复杂度为O(1)。

Python代码实现如下:

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None


def is_cycle(head):
    p1 = head
    p2 = head
    while p2 is not None and p2.next is not None:
        p1 = p1.next
        p2 = p2.next.next
        if p1 == p2:
            return True
    return False


node1 = Node(5)
node2 = Node(3)
node3 = Node(7)
node4 = Node(2)
node5 = Node(6)
node1.next = node2
node2.next = node3
node3.next = node4
node4.next = node5
node5.next = node2
print(is_cycle(node1))

扩展问题:如果链表有环,如何求出环的长度以及入环节点?

求环长:当两个指针首次相遇,证明链表有环后,两指针继续循环前进,并统计前进的循环次数,直到两个指针第2次相遇。此时,统计的前进次数就是环长。

求入环节点:假设从链表头节点到入环点距离是D,入环点到首次相遇点距离是S1,首次相遇点到入环点为S2。

由结论可得,把其中一个指针放回头节点的位置,另一个指针保持在首次相遇点,两个指针都是每次向前走1步。那么它们最终相遇的节点,就是入环节点。

本文参考整理自《漫画算法:小灰的算法之旅》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值