Linked List Cycle II
Detect a loop with fast and slow pointers, then find where it starts using Floyd's algorithm
Problem Statement
Given the head of a linked list, return the node where a cycle begins. If there is no cycle, return null.
You must solve it using O(1) memory.
Input: 3 → 2 → 0 → -4
↑ ↓
←————————
Output: the node with value 2 (index 1)
Input: 1 → 2 → 1 (cycle back to the head)
Output: the node with value 1
Input: 1 → null
Output: nullIntuition
There are two questions here: is there a cycle? and where does it start? The first is easy; the second is where the famous trick lives.
Part 1 — detecting the cycle
Fast and slow pointers must collide inside a loop
Run slow one step at a time and fast two steps at a time.
- No cycle →
fastreachesnulland you are done. - Cycle → both pointers are eventually trapped inside the loop. Each step,
fastgains exactly one position onslow. On a circular track, a gap that shrinks by one every step must reach zero — so they must meet. There is no way to skip past.
That "gain exactly one per step" argument is why fast moves by two and not three. With a larger stride the gap changes by more than one and could step over slow on a loop whose length shares a factor with the stride.
Part 2 — locating the cycle's start
This is the surprising part. Label the distances:
head ──── F ────► S ──── a ────► M
▲ │
└───── b ───────┘
F = distance from head to the cycle start S
a = distance from S forward to the meeting point M
b = remaining distance from M back around to S
C = a + b = cycle lengthWhen they meet:
slowhas travelledF + a(it enters the loop and walksa).fasthas travelledF + a + nCfor some whole number of extra lapsn ≥ 1.fastmoved twice as far:2(F + a) = F + a + nC.
Simplify: F + a = nC, so F = nC - a = (n-1)C + (C - a) = (n-1)C + b.
What that equation means in plain English
F = (n-1)C + b
The distance from the head to the cycle start equals the distance from the meeting point to the cycle start (plus some whole laps, which change nothing since you end up in the same place).
So: put one pointer back at the head, leave the other at the meeting point, and advance both one step at a time. They meet exactly at the cycle's entrance.
Watch it run
2)Approach
Phase 1 — find a meeting point
Advance slow by one and fast by two while fast and fast.next exist. If they ever become the same node, a cycle exists. If fast reaches null, return null.
Phase 2 — walk to the entrance
Reset one pointer to head. Move both one step at a time. Where they meet is the start of the cycle.
Solution
from typing import Optional
class ListNode:
def __init__(self, val: int = 0, next: Optional["ListNode"] = None):
self.val = val
self.next = next
def detect_cycle(head: Optional[ListNode]) -> Optional[ListNode]:
"""Return the node where the cycle begins, or None."""
slow = fast = head
# Phase 1: find a meeting point inside the cycle.
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow is fast:
break
else:
return None # fast ran off the end — no cycle
# Phase 2: F == b, so both pointers reach the entrance together.
finder = head
while finder is not slow:
finder = finder.next
slow = slow.next
return finderPython's while/else
The else on a while loop runs only when the loop finished without hitting break. Here that means fast reached the end of the list, so there is no cycle. It expresses "the loop completed normally" without an extra flag — which is what the TypeScript version needs met for.
The hash-set version
If O(n) memory is acceptable, the problem becomes almost trivial:
def detect_cycle_set(head: Optional[ListNode]) -> Optional[ListNode]:
seen = set()
node = head
while node:
if id(node) in seen:
return node # first revisited node IS the cycle start
seen.add(id(node))
node = node.next
return NoneWorth mentioning in an interview as the obvious baseline before presenting Floyd's — it shows you know the trade-off rather than just the trick.
Complexity Analysis
Time Complexity
O(n)
Space Complexity
O(1)
- Time — phase 1 takes at most
O(n)steps (slowcannot travel further than the list length plus one lap); phase 2 takesF ≤ nsteps. - Space — four references. This is the whole reason to prefer Floyd's over the hash set, which needs
O(n).
Edge Cases
Related Problems
- Middle of the Linked List — the gentle introduction to fast and slow pointers
- Intersection of Two Linked Lists — pointers synchronised by a distance argument
- Reverse Linked List — careful pointer handling