在链表中检测周期/循环的不同方法

问题描述

所以我知道Floyd的周期检测算法,但是在解决问题时,我想出了另一种方法解决它。

在遍历链接列表时,如果我们可以将每个节点的“ nextpointer ”存储在向量/列表中,则在任何元素的频率大于或等于1的情况下,可以进行计数。 如果向量/列表中的任何值多次出现,则基本上意味着单个节点被指向两次(或多次),因此,它成为一个循环。

我无法用Python 3编写相同的代码。如果大家都能帮助我,我将不胜感激。 谢谢。

class Node:
    head = None

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

def findMergeNode(head1,head2):
    a = set()
    b = set()
    while (head1 and head2):
        a.add(head1)
        head1 = head1.next        
        b.add(head2)
        head2 = head2.next
    if (a.intersection(b)):
        return a.intersection(b)

解决方法

您提出的算法可以使用,但是

  1. 它需要 O(n)空间,并且
  2. 在列表(向量)中进行查找需要 O(n)时间

可以通过使用集合来解决第二个问题,但是第一个问题仍然是主要缺点。

这是一套简单的实现:

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

    def add(self,val):
        self.next = Node(val)
        return self.next  # to allow chaining

    def hascycle(self):
        node = self
        visited = set()
        while node:
            if node in visited:  # been here before!
                return True
            visited.add(node)
            node = node.next
        return False

# Demo graph: a -> b -> c -> d -> e -> b
a = Node("a")
e = a.add("b").add("c").add("d").add("e")
# make a back reference from e to b:
e.next = a.next
print(a.hascycle())  # True

请注意visited的大小如何与链表本身处于相同的数量级。当然,当未检测到任何周期时,对 all 节点的引用将存储在集合中。

弗洛伊德算法的优点在于,它仅使用常量空间(当然不计算列表本身)。因此,与链表的大小无关,它将始终使用相同的空间进行操作。