Linked List Cycle

Linked List Cycle#

Problem#

Given the head of a singly linked list, determine whether the list contains a cycle. A cycle exists if some node can be reached again by continuously following next pointers.

Example#

For 3 -> 2 -> 0 -> -4 where -4 points back to node 2, the answer is True. For a plain list 1 -> 2 that ends in None, the answer is False.

Brute force#

Store every visited node in a hash set. If you ever revisit a node, there is a cycle. This works but uses O(n) extra space.

Optimal approach#

Floyd’s tortoise and hare uses two pointers moving at different speeds. The slow pointer advances one node per step, the fast pointer two. If the list ends, the fast pointer reaches None and there is no cycle. If there is a cycle, the fast pointer eventually laps the slow pointer and they land on the same node. Meeting means a cycle exists. This needs only O(1) space.

Solution#

 1class ListNode:
 2    def __init__(self, val=0, next=None):
 3        self.val = val
 4        self.next = next
 5
 6
 7def has_cycle(head: ListNode | None) -> bool:
 8    slow = fast = head
 9    while fast and fast.next:
10        slow = slow.next
11        fast = fast.next.next
12        if slow is fast:
13            return True
14    return False
15
16
17a, b, c, d = ListNode(3), ListNode(2), ListNode(0), ListNode(-4)
18a.next, b.next, c.next, d.next = b, c, d, b  # d links back to b: cycle
19print(has_cycle(a))  # True
20
21x, y = ListNode(1), ListNode(2)
22x.next = y
23print(has_cycle(x))  # False

Complexity#

  • Time: O(n), the pointers meet within one traversal.
  • Space: O(1).

This is the classic fast and slow pointers problem. Keep going with the 60-day challenge.