From dde630c1efba2ded3341eee6327836f1cd7839a7 Mon Sep 17 00:00:00 2001 From: xingzihai Date: Thu, 15 Oct 2026 06:50:58 +0000 Subject: [PATCH] fix(linked_list): use Floyd's cycle detection in has_loop (O(1) space) (#15576) Replace the O(n)-auxiliary-space visited-set traversal in Node.has_loop with Floyd's tortoise-and-hare cycle detection, which uses only constant auxiliary space. Loop detection still compares node references, not data values, and covers acyclic lists, self-loops, loops to earlier nodes, loops involving the final node, and duplicate data values. Fixes #15576 --- data_structures/linked_list/has_loop.py | 33 +++++++++++++++++++++---- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/data_structures/linked_list/has_loop.py b/data_structures/linked_list/has_loop.py index a25204e3c4ce..10d9aa9893de 100644 --- a/data_structures/linked_list/has_loop.py +++ b/data_structures/linked_list/has_loop.py @@ -27,6 +27,9 @@ def __iter__(self) -> Iterator[Any]: def has_loop(self) -> bool: """ A loop is when the exact same Node appears more than once in a linked list. + Uses Floyd's tortoise-and-hare cycle detection, so only constant + auxiliary space is used regardless of list length. + https://en.wikipedia.org/wiki/Cycle_detection#Floyd's_tortoise_and_hare >>> root_node = Node(1) >>> root_node.next_node = Node(2) >>> root_node.next_node.next_node = Node(3) @@ -37,11 +40,14 @@ def has_loop(self) -> bool: >>> root_node.has_loop True """ - try: - list(self) - return False - except ContainsLoopError: - return True + slow = self + fast = self + while fast is not None and fast.next_node is not None: + slow = slow.next_node if slow is not None else None + fast = fast.next_node.next_node + if slow is fast: + return True + return False if __name__ == "__main__": @@ -61,3 +67,20 @@ def has_loop(self) -> bool: root_node = Node(1) print(root_node.has_loop) # False + + # Self-loop: a node points to itself + root_node = Node(1) + root_node.next_node = root_node + print(root_node.has_loop) # True + + # Loop involving the final node + root_node = Node(1) + root_node.next_node = Node(2) + root_node.next_node.next_node = Node(3) + root_node.next_node.next_node.next_node = root_node.next_node.next_node + print(root_node.has_loop) # True + + # Duplicate data values in different nodes must not be mistaken for a loop + root_node = Node(1) + root_node.next_node = Node(1) + print(root_node.has_loop) # False