Linked List Cycle Detection: Slow and Fast Pointers
By Hourly DSA · · 4 min read
To detect a cycle in a singly linked list, move one pointer one step at a time and another two steps at a time. If they meet after moving, the list contains a cycle. If the faster pointer reaches the end, the list has no cycle.
This is Floyd's cycle detection algorithm, often called the tortoise and hare algorithm. It uses constant extra space because it does not store every visited node.
A cycle repeats a node, not just a value
Consider nodes connected like this:
A → B → C → D → E
↑ |
└───────┘
E points back to C. Following next references produces A, B, C, D, E, C, D, E, ... and never reaches the end.
Two different nodes can hold the same value without forming a cycle. For example, three separate nodes containing 7 → 2 → 7 → null form a normal terminating list. Compare node identity, meaning whether both pointers refer to the same node, rather than comparing stored values.
A set of visited node identities can detect repetition too. That method is direct, but it uses O(n) extra space for n distinct reachable nodes. Slow and fast pointers avoid that storage.
Trace both pointers
Start both pointers at A, then compare them only after advancing:
| Round | Slow, moving one step | Fast, moving two steps |
|---|---|---|
| Start | A | A |
| 1 | B | C |
| 2 | C | E |
| 3 | D | D |
They meet at D, so a cycle exists. D is not the cycle's entry; C is. Detecting a cycle and locating its start are separate tasks.
Comparing the initial pointers before either moves would incorrectly report a cycle for every nonempty list, because both begin at the head.
Check that both fast steps are safe
For detection, the pseudocode is:
slow = head
fast = head
while fast is not null and fast.next is not null:
slow = slow.next
fast = fast.next.next
if slow is the same node as fast:
return true
return false
The guard checks fast before reading its next reference, and checks that next node before taking the second step. This handles an empty list and a one-node list that ends at null.
A node pointing to itself is different: both pointers return to it after advancing, so the algorithm correctly reports a cycle.
Why does the faster pointer catch the slower one?
Once both pointers are inside a cycle of length c, their relative position changes by one node per round. Fast advances two nodes while slow advances one.
Think of the gap modulo c. Each round changes it by one, so within at most c rounds the gap becomes zero and both pointers occupy the same node. Fast cannot keep skipping over slow forever under this one-step relative movement.
Reaching the cycle and closing the gap take O(n) time in total, where n is the number of distinct nodes reachable from the head. Only two node references are needed, giving O(1) auxiliary space.
The CP-Algorithms explanation of Floyd's algorithm gives a formal derivation of the meeting and entry steps.
How do you find the cycle's starting node?
After a meeting, reset one pointer to the head. Leave the other at the meeting node. Move both one step at a time until they meet again, comparing before each advance so an entry at the head is handled too.
In our example, reset one pointer to A and leave the other at D:
A and D
B and E
C and C
They meet at C, the cycle entry.
To see why, let the distance from the head to the entry be a. At the first detection meeting, slow has traveled t steps and fast has traveled 2t. Their distance difference, t, is a multiple of the cycle length.
Moving another a steps from the meeting therefore lands at the entry: the position within the cycle becomes t modulo its length, which is zero. The pointer starting at the head reaches the entry in exactly a steps too.
Which cases should you reason through?
Use an empty list, a single terminating node, a self-loop, a cycle beginning at the head, and a cycle after a noncyclic prefix. Also include distinct nodes with equal values to catch an identity-comparison mistake.
For a terminating list of four nodes, the fast pointer reaches null. No amount of repeated values changes that outcome.
This pattern is related to two-pointer reasoning, but the proof comes from relative movement inside a cycle. Practice explaining that proof in a few sentences with Hourly DSA, then use the mistake-review guide to capture whichever edge case exposed a gap in your understanding.
Read next
Compare pointer-cycle reasoning with cycle detection as undirected graph edges arrive.