Linked List Cycle
A fast pointer laps a slow one if and only if there's a loop.
Approach
Advance one pointer by one and another by two each step. If they ever meet, there's a cycle; if the fast pointer reaches the end, there isn't. Floyd's trick detects loops in O(1) space, unlike a visited-set approach.
Time complexity
O(n)
Space complexity
O(1)
Common mistake
Checking pointer identity before advancing, or not guarding fast.next before taking two steps.
Interactive walkthrough — step through it below, free and without an account
Problem
Given the head of a singly linked list, determine whether repeatedly following next eventually revisits a node. Return true when the list loops back to an earlier node; otherwise return false when traversal reaches null.
Examples
Input: head = [3,2,0,-4], pos = 1
Output: true
2, so traversal cycles through 2 → 0 → -4.Input: head = [1,2], pos = -1
Output: false
null, so the traversal terminates.Problem
Problem
Given the head of a singly linked list, determine whether repeatedly following `next` eventually revisits a node. Return `true` when the list loops back to an earlier node; otherwise return `false` when traversal reaches `null`.
Problem and Goal
Learning goal: Recognize when a linked-list traversal contains a loop and why revisiting a node matters.
Core idea
A normal singly linked list eventually reaches null. A cyclic list never does: its next pointers repeatedly send traversal through nodes that were already visited. The task is to detect that structural behavior, not merely to find duplicate values, because two different nodes may contain the same value.
Algorithm plan
- Start two references at the head:
slowandfast. - Move
slowone link at a time. - Move
fasttwo links at a time. - Report a cycle if the references become identical.
- Report no cycle if
fastorfast.nextisnull.
Micro-example
For 3 → 2 → 0 → -4 → 2, the final arrow returns to the node containing 2.
For 1 → 2 → null, every traversal eventually stops.
Pitfalls
- Compare node identity, not node values.
- An empty list has no cycle.
- A single node pointing to itself is still a cycle.
Recap
- Cycles are about repeated nodes, not repeated values.
- Termination at
nullproves that no cycle exists. - Floyd's method detects both outcomes with two moving references.
Problem and Goal
Follow links, not values
A cycle exists when a `next` pointer leads back to an existing node. Equal values alone do not imply a cycle.
The algorithm compares references such as `slow === fast`, never just `slow.val === fast.val`.
Key Idea: A Pointer Race
Learning goal: Understand why a fast pointer must meet a slow pointer exactly when a loop exists.
Core idea
Imagine the list as a straight path leading into a circular track. Before entering the track, both pointers move forward. Once both are on the circular portion, fast gains one node per round on slow, so it eventually laps and meets it. If there is no circular portion, fast simply reaches the end first.
Key insight
Inside a loop, the distance between the pointers changes by one position modulo the loop length. Repeatedly subtracting one eventually produces zero.
Data structure model
slowadvances byslow = slow.next.fastadvances byfast = fast.next.next.- The test is made after both have advanced.
- Before taking two steps, verify
fast !== nullandfast.next !== null.
Micro-example
In 3 → 2 → 0 → -4 → 2, after a few rounds the pointers occupy the same -4 node.
In 1 → 2 → null, fast.next is eventually null, so the loop stops safely.
Pitfalls
- Checking pointer identity before the first movement can misclassify
slow === fastat the head. - Moving
fasttwice without guardingfast.nextcan dereferencenull. - The speed difference is one node per iteration, which is what guarantees a meeting.
Recap
- A loop turns the suffix into a circular track.
fastlapsslowif and only if that track exists.- The null guard protects the two-step movement.
Key Idea: A Pointer Race
Once both pointers enter the cycle, positions repeat modulo the cycle length.
A one-node speed advantage eventually closes any gap.
Main Approach and Correctness
Learning goal: Translate the pointer race into a safe, implementation-ready algorithm.
Core idea
Initialize both references at the head, then perform a guarded movement loop. The guard is evaluated before fast.next.next, because fast may already be null or may point to the final node. After each complete movement, pointer identity is checked. A meeting is conclusive evidence of a cycle because two traversals starting at the same head can only occupy the same node after different progress if the structure loops.
Algorithm plan
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 fast:
return true
return falseWhy it works
The only way the faster reference can catch the slower one is for the path ahead to wrap around. A finite acyclic path has no place to wrap.
Micro-example
For the cycle 3 → 2 → 0 → -4 → 2, both pointers enter the loop and eventually coincide.
Pitfalls
- The loop guard belongs before the two-step assignment.
- Use reference identity, such as
slow === fast. - Do not allocate a set of visited nodes if constant space is required.
Recap
- Guard, advance both, then compare.
- A meeting proves a loop; a null guard proves termination.
- The method uses constant auxiliary space.
Main Approach and Correctness
| Approach | Time | Extra space | Core trade-off |
|---|---|---|---|
| Fast & slow pointers | O(n) | O(1) | Uses a speed difference to detect a meeting |
| Visited set | O(n) | O(n) | Stores every node identity encountered |
Walkthrough: One Complete Cycle
Learning goal: Trace every pointer movement on the example 3 → 2 → 0 → -4 → 2.
Core idea
The tail does not point to a new node; it points back to the node containing 2. We will label nodes by identity so the repeated destination is visible. Both pointers begin at the head, but we do not declare a cycle merely because they initially share that node. Instead, each round advances slow once and fast twice, then checks whether they meet.
Data structure model
n1stores3and points ton2.n2stores2and points ton3.n3stores0and points ton4.n4stores-4and points back ton2.- The cycle is
n2 → n3 → n4 → n2.
Micro-example
Round 1: slow reaches n2; fast reaches n3.
Round 2: slow reaches n3; fast reaches n2.
Round 3: both reach n4, so the references are identical.
Pitfalls
n2appears again as a destination, but it is one stable node, not a copied value.fastmust take two valid links at every round.- The meeting can happen anywhere inside the loop, not necessarily at its entry.
Recap
- The visualization tracks node IDs and pointer positions.
- The pointers meet at
n4after advancing. - That meeting returns
true.
Walkthrough: One Complete Cycle
Animate Floyd's algorithm on the example 3 → 2 → 0 → -4 → 2, where the tail links back to the node containing 2.
Pitfalls and Edge Cases
Learning goal: Prevent the two implementation mistakes that most often break cycle detection.
Core idea
The safest loop structure checks whether two steps are available before moving fast. It then advances both pointers and compares their identities. This ordering handles empty lists, one-node lists, and ordinary terminating lists without special-case code.
Algorithm plan
- Empty list:
headisnull, so the loop never starts and the answer isfalse. - One node to
null:fast.nextisnull, so the answer isfalse. - One node to itself: both pointers move back to that same node, so the answer is
true. - Any longer cycle: continue until the references meet.
Common pitfall
Checking slow === fast before advancing is wrong when both start at head; every nonempty list would appear cyclic immediately.
Null guard
Never evaluate fast.next.next unless both fast and fast.next are non-null.
Micro-example
For 1 → 2 → null, the initial guard fails because fast.next eventually becomes null.
For 7 → 7, the self-link makes the pointers meet after a movement.
Pitfalls
- Do not compare
valfields. - Do not forget that
head = nullis valid. - Do not use a visited set when the target space is
O(1).
Recap
- Guard before the two-step move.
- Compare after advancing.
- Identity, not value equality, determines a meeting.
Pitfalls and Edge Cases
Which loop is safe and correctly ordered for Floyd's cycle check?
Complexity and Wrap-up
Learning goal: Explain why Floyd's method meets the target complexity and summarize the reusable pattern.
Core idea
The pointers may traverse a short non-cyclic prefix and then move around a cycle. Each movement advances through an existing node, and the fast pointer either reaches null or catches the slow pointer after a linear number of steps. The algorithm stores only two references, so its auxiliary memory does not grow with the list size.
Algorithm plan
- Maintain
slowandfastonly. - Spend constant work per loop iteration.
- Stop on either a guarded null condition or pointer identity equality.
- Return the corresponding Boolean result.
Micro-example
The walkthrough visits a constant number of pointer states for its four-node structure.
For a list with n nodes, the same process scales linearly rather than storing all n identities.
Pitfalls
- A visited-set solution is correct but uses
O(n)extra space. - Big-O counts nodes and pointer operations, not the numeric values stored in nodes.
- The method detects existence; finding the cycle entry requires a second Floyd phase.
Recap
- Time complexity:
O(n). - Auxiliary space:
O(1). - Fast laps slow if and only if a loop is reachable.
- The reusable pattern is a speed difference plus a guarded identity check.
Complexity and Wrap-up
Summarize the cost of Floyd's cycle detection and contrast its space usage with a visited set.
Now try it on your own problem
Paste any LeetCode problem — or one of your own — and codebrew builds a walkthrough like this one for it.
Build a lesson from any problem
