Code › algorithm-study
LeetCode 141 - Linked List Cycle
Detecting a cycle in a singly-linked list using Floyd's two-pointer algorithm in Python
Given the head of a singly-linked list, this Easy problem asks to determine if the list contains a cycle. Rather than storing visited node references in a hash set, I used Floyd’s cycle-finding algorithm with two pointers moving at different speeds to achieve O(1) auxiliary space.
Problem link and explanation
- Problem: 141. Linked List Cycle
- Summary: Given the
headof a linked list, returnTrueif there is a cycle where a node can be reached again by continuously followingnextpointers. Otherwise, returnFalse.
While keeping a set of visited nodes takes O(n) space, the two-pointer approach leverages the property that within a cycle, a faster pointer will always catch up to a slower pointer one step at a time.
Approach
The slow pointer advances by one step per iteration while the fast pointer advances by two steps.
slow = head
fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
return True
return False
- Initialization: Start both pointers at
head. If the list is empty or has only one node without a loop, returnFalseimmediately. - Traversal: Advance
slow = slow.nextandfast = fast.next.nextwhilefastandfast.nextare notNone. - Collision check: If a cycle exists, the relative gap between
fastandslowdecreases by 1 on each iteration untilslow == fast, confirming the cycle. - Termination: If
fastreaches the end of the list (None), no cycle exists, and the function returnsFalse.
Complexity analysis
- Time complexity: O(n)
- If there is no cycle,
fastreaches the end in n/2 steps. If a cycle exists,fastcatchesslowwithin at most one full cycle length after entering the loop.
- If there is no cycle,
- Space complexity: O(1)
- Operates with only two pointer variables without allocating auxiliary data structures.
Implementation code
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def hasCycle(self, head) -> bool:
if not head or not head.next:
return False
slow = head
fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
return True
return False
Summary and reflection
Floyd’s algorithm provides an elegant solution for cycle detection by converting a graph traversal problem into a relative speed collision check. Because the distance between the two pointers strictly decreases by 1 in each step inside the cycle, convergence is guaranteed without danger of an infinite loop.