【问题标题】:Detecting loop in a Linked List检测链表中的循环
【发布时间】:2011-12-04 01:53:15
【问题描述】:

如何仅使用单指针检测链表中的循环? (不想要慢而快的指针(兔子和乌龟))

【问题讨论】:

  • 如果答案是兔子和乌龟算法,这已经是一个非常人为的问题了。
  • “仅使用单指针”是什么意思?您已经使用了一个指针来存储指向列表头部的指针;您是否可以提出除此之外的任何指示?
  • @templatetypedef:这里只能表示两个指针:两个指针访问链表。

标签: loops data-structures linked-list


【解决方案1】:

如果您不介意额外的 O(N) 内存,您可以使用 hastable 来存储访问过的节点,因为您沿着链表前进。

在每个节点上,您检查该节点是否已存在于哈希表中。如果是这样,您已经找到了一个循环。否则,您将其添加到哈希表并移动到下一个节点。

【讨论】:

  • 但这不是需要多个指针(哈希表中存储的每个节点一个指针吗?)
  • @templatetypedef:是的。我将“使用单个指针”理解为使用单个指针来迭代列表而不是使用两个指针。这使用单个指针进行迭代,但我们仍在存储指向所有访问节点的指针 - 因此我在回答中提到了 O(n) 内存。我认为 OP 可能会很好。
【解决方案2】:

如果您的节点由值和指向下一个节点的指针组成,您可以使用列表创建指向第一个节点的指针。您可以在每个节点上检查指针是否与指向第一个节点的指针具有相同的值。

【讨论】:

  • 如果循环回到列表的中间而不是前面怎么办?
【解决方案3】:

Brent's algorithm 显然是这里最好的:对于无循环列表,它只访问列表一次,而 Floyd 的龟兔赛跑需要重新访问一半的节点。对于带有循环的列表,它在循环中的“旋转”时间永远不会比 Floyd 长;在最好的情况下只需要一个周期,而弗洛伊德需要很多。考虑一个长的无循环序列,然后是一个长度为 1 的循环。在这种情况下,布伦特的最佳情况是在循环访问一次后检测循环——因此每个节点只访问一次;而 Floyd 必须平均访问每个节点 3 次。

基本思路是访问链表,比较当前节点的指针和一个已经访问过的节点。也就是说,每个访问节点进行一次指针比较。指针按照简单的逻辑不时更新。

【讨论】:

  • @templatetypedef:只有一个指针在链表中进行筛选。另一个不时设置为第一个的值。
【解决方案4】:
class Solution:
    def hasCycle(self, head: ListNode) -> bool:
        if not head:
            return False
        current_node = head
        seen = set()
        while (current_node not in seen):
            # This means there is a tail
            if current_node.next == None:
                return False
            seen.add(current_node)
            current_node = current_node.next
        # current_node would be the start of the cycle
        return True

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-06
    • 2023-03-15
    • 2016-08-19
    • 1970-01-01
    相关资源
    最近更新 更多