1- from __future__ import annotations
2-
3- from collections .abc import Iterator
4- from typing import Any
5-
6-
7- class ContainsLoopError (Exception ):
8- pass
9-
10-
11- class Node :
12- def __init__ (self , data : Any ) -> None :
13- self .data : Any = data
14- self .next_node : Node | None = None
15-
16- def __iter__ (self ) -> Iterator [Any ]:
17- node = self
18- visited = set ()
19- while node :
20- if node in visited :
21- raise ContainsLoopError
22- visited .add (node )
23- yield node .data
24- node = node .next_node
25-
26- @property
27- def has_loop (self ) -> bool :
28- """
29- A loop is when the exact same Node appears more than once in a linked list.
30- >>> root_node = Node(1)
31- >>> root_node.next_node = Node(2)
32- >>> root_node.next_node.next_node = Node(3)
33- >>> root_node.next_node.next_node.next_node = Node(4)
34- >>> root_node.has_loop
35- False
36- >>> root_node.next_node.next_node.next_node = root_node.next_node
37- >>> root_node.has_loop
38- True
1+ @property
2+ def has_loop (self ) -> bool :
393 """
40- try :
41- list (self )
42- return False
43- except ContainsLoopError :
44- return True
4+ Detect whether the linked list contains a cycle using Floyd's
5+ Cycle-Finding Algorithm (Tortoise and Hare).
456
7+ Time Complexity: O(n)
8+ Auxiliary Space: O(1)
9+ """
10+ slow = self
11+ fast = self .next
4612
47- if __name__ == "__main__" :
48- root_node = Node (1 )
49- root_node .next_node = Node (2 )
50- root_node .next_node .next_node = Node (3 )
51- root_node .next_node .next_node .next_node = Node (4 )
52- print (root_node .has_loop ) # False
53- root_node .next_node .next_node .next_node = root_node .next_node
54- print (root_node .has_loop ) # True
55-
56- root_node = Node (5 )
57- root_node .next_node = Node (6 )
58- root_node .next_node .next_node = Node (5 )
59- root_node .next_node .next_node .next_node = Node (6 )
60- print (root_node .has_loop ) # False
13+ while fast is not None and fast .next is not None :
14+ if slow is fast :
15+ return True
16+ slow = slow .next
17+ fast = fast .next .next
6118
62- root_node = Node (1 )
63- print (root_node .has_loop ) # False
19+ return False
0 commit comments