DSA sheet · Linked List · Fast & slow pointer pattern

Linked List Cycle II

The previous problem only asked whether there is a cycle. This one asks where it starts. The teacher reuses the same two runners to find a meeting point, and then adds one surprising trick: put one pointer back at the head, move both one step at a time, and they meet exactly at the start of the cycle. The code is tiny. The real lesson is the proof of why the trick works, because, as she says, writing this code in an interview without being able to explain it doesn't make sense. So the proof gets the most space on this page.

Every part below follows the same order:
① the question in simple words → ② what the constraints tell us → ③ intuition → ④ building the logic (and the proof) → ⑤ approach steps → ⑥ code → ⑦ code line by line → ⑧ dry run → ⑨ complexity & remember

Part 0 · Before starting

Linked list basics

A linked list is a chain of nodes. Each node has a val (the number) and a next (the node after it). The last node's next is None. We are given only the first node, called head.

given by LeetCode, don't write this in the solution
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next
[1] → [2] → [3] → [4] → None
 ↑
head

Cycle words used on this page

[1] → [2] → [3] → [4] → [5] → [6]
             ↑                   │
             └───────────────────┘
tail part: 1, 2     cycle start: 3     loop: 3 4 5 6  (K = 4)

Fast and slow pointers (recap from Cycle I and Middle of List)

Part A · Find the cycle start with fast and slow pointers

LeetCode 142

1The question in simple words

You get the head of a linked list. If it has a cycle, return the node where the cycle starts. If it has no cycle, return None (null). Don't change the list.

The teacher goes through LeetCode's three examples:

Example 1 → return the node 2
[3] → [2] → [0] → [-4]
       ↑            │
       └────────────┘
Example 2 → return the head (1)
[1] → [2]
 ↑     │
 └─────┘
Example 3 → return None
[1] → None

LeetCode shows a number pos (the index the last node links back to). The teacher points out it is not passed to your function. It only helps you read the example.

2What the constraints tell us

3Intuition: why this pattern, and the two-phase idea

The teacher first picks the pattern by elimination. The linked list patterns are: basic operations, fast and slow pointers, reversal, and merge/sort.

The plan has two phases:

  1. Phase 1, detect: run slow (1 step) and fast (2 steps) until they meet. The meeting node proves there is a cycle, but it is usually not the start.
  2. Phase 2, locate: leave slow at the meeting node. Put a second pointer at head. Move both at the same speed, 1 step each. The node where they meet is the cycle start.

4Building the logic, and the proof

Phase 1 gives a meeting point, not the start

Take this list (the cycle starts at node 3):

[1] → [2] → [3] → [4] → [5] → [6]
             ↑                   │
             └───────────────────┘

slow/fast go: (1,1) → (2,3) → (3,5) → (4,3) → (5,5). They meet at 5. But the loop starts at 3. So returning the meeting node would be wrong. The meeting node only tells us "a cycle exists".

Phase 2: reset one pointer to head, same speed

Keep slow on 5. Start a new pointer at head (the teacher reuses fast for this, or calls it a "new node" pointer). Now both move 1 step:

Why should that work? It looks like magic. Here is the proof, the way the teacher builds it.

The distance proof

Give names to three distances (all measured in "steps", i.e. number of next links followed):

         a = 2 steps                 b = 2 steps
   [1] ─────→ [2] ─────→ [3] ─────→ [4] ─────→ [5]
   head                   S ↑                    │ M
                            │                    │
                            └───── [6] ←─────────┘
                                 c = 2 steps

   a = head → S   (length of the tail part)
   b = S → M      (from the cycle start to the meeting point, going forward)
   c = M → S      (the rest of the loop, from the meeting point back to the start)
   K = b + c      (cycle length; here K = 4)

S = cycle start, M = meeting point of phase 1.

  1. How far did slow walk until the meeting? From head to S (a), then from S to M (b). So slow = a + b.
  2. How far did fast walk? The same a and b, plus some whole trips round the loop, because it went round and came up behind slow. One trip is K steps. It might have gone round once, twice, or more, so say n full trips: fast = a + b + n·K (n ≥ 1).
  3. Fast always walks twice as far as slow (that's what speed 2 vs 1 means, the same fact that puts slow at the middle in the middle-of-list problem): fast = 2 · slow.
  4. Put the two together: 2(a + b) = a + b + n·K.
  5. Take away a + b from both sides: a + b = n·K.
  6. Move b across: a = n·K − b.

What does n·K − b mean on the picture? Take the teacher's case n = 1: a = K − b. The whole loop is K. Remove the part b (S → M). What's left is exactly c, the walk from M forward back to S. So:

The key facta = c (when n = 1): the distance from head to S equals the distance from M forward to S.
So if one pointer starts at head and another starts at M, and both take one step at a time, after exactly a steps both stand on S.

Check it on the picture: a = 2 (1 → 2 → 3) and c = 2 (5 → 6 → 3). Equal ✓. And slow walked a + b = 4, fast walked 8 = 4 + 1·4, so n = 1 ✓.

Doubt 1: what if fast went round more than once (n = 2, 3, …)?
→ Write a = n·K − b = (n − 1)·K + (K − b) = (n − 1)·K + c. The pointer at M walks c steps to reach S, then (n − 1) full trips round the loop, and each full trip ends back at S. So after a steps it is still on S, exactly when the head pointer arrives there. Example: list 1 → 2 → 3 → 4 → 5 → 6 → 7 → back to 6. Here a = 5, K = 2. Phase 1 meets at 7 after 6 steps (slow 6 = a + b with b = 1; fast 12 = 6 + 3·2, so n = 3). Phase 2: head pointer goes 1→2→3→4→5→6; the other goes 7→6→7→6→7→6. Both on 6 ✓.
Doubt 2: slow walked only a + b? Couldn't slow also go round the loop before being caught?
→ No. When slow first enters the loop at S, fast is already somewhere in the loop, at most K − 1 steps "behind" slow (counting forward from fast to slow). Each step the gap shrinks by 1 (slow +1, fast +2). So fast catches slow in at most K − 1 steps, before slow can finish one trip. That's why b is less than K and slow's distance is just a + b. One exception: if the loop starts at head (a = 0), both runners start together on S and the first meeting we check for happens after slow's first full lap, back on S, so b = K. The formula still works (a + b = 0 + K = 1·K). (This detail is an addition to the teacher's proof; it's what makes "slow = a + b" safe.)
Doubt 3: could the two pointers in phase 2 meet somewhere before S?
→ No. Before step a, the head pointer is still in the tail part (outside the loop), while the other pointer is always inside the loop. A node can't be both inside and outside the loop, so they can't be on the same node. The first time the head pointer enters the loop is at S, after exactly a steps, and that is when the other pointer is also on S.
Doubt 4: why move both at the same speed in phase 2?
→ The proof says "both walk a steps". That only works if they walk the same number of steps, i.e. one step each per round. If one still moved 2 at a time, after a rounds it would have walked 2a, and the equation no longer lands on S.
Doubt 5: is there a simpler (non-optimal) way?
→ Yes, the hash set from Cycle I. Walk from head and store each node; the first node you see twice is the cycle start, because the first repeated node is where the loop closes. It is O(n) time but O(n) space. The two-pointer method keeps O(1) space, which the follow-up asks for. (The teacher doesn't code the set version in this video; it's shown in the revision part and tested.)

The special case: cycle at the head (Example 2)

Here a = 0. Phase 1 meets somewhere in the loop; with a = 0 the proof says b = n·K, which means M is a whole number of laps away from S, i.e. M is S itself (the head). In practice both runners start on head and meet again on head after slow's first lap (Doubt 2). In phase 2 the new pointer starts at head and slow is already on head, so they are equal before any move. That's why phase 2 must check while slow is not ptr before moving: we return head straight away ✓.

5Approach steps

  1. slow = fast = head.
  2. While fast and fast.next exist: slow moves 1, fast moves 2.
  3. If slow is fast (they met): set ptr = head. While ptr is not slow, move both one step. Return ptr (the cycle start).
  4. If the first loop ends without meeting → no cycle → return None.

6Code (Python)

Linked List Cycle II, fast and slow + reset to head
class Solution:
    def detectCycle(self, head):
        slow = head
        fast = head
        while fast is not None and fast.next is not None:
            slow = slow.next              # phase 1: speed 1
            fast = fast.next.next         #          speed 2
            if slow is fast:              # met inside the loop
                ptr = head                # phase 2: new pointer at head
                while ptr is not slow:    # same speed until they meet
                    ptr = ptr.next
                    slow = slow.next
                return ptr                # this is the cycle start
        return None                       # fast fell off: no cycle

7Code line by line

linewhat it means
slow = head fast = headBoth runners start together at head.
while fast is not None and fast.next is not None:Fast can take two more steps. If not, the list has an end, so no cycle. Handles the empty list too.
slow = slow.next fast = fast.next.nextPhase 1 movement: 1 step and 2 steps. Fast's distance is always 2 × slow's, which the proof relies on.
if slow is fast:They stand on the same node M. A cycle exists. Checked after moving, because they're trivially equal at the start.
ptr = headThe second walker starts at head. It needs a steps to reach S.
while ptr is not slow:Check before moving, so a cycle starting at head (a = 0) returns immediately.
ptr = ptr.next slow = slow.nextPhase 2: both at speed 1. From M, slow needs c (+ whole laps) steps to reach S; ptr needs a. The proof says these are the same.
return ptrThey met. The proof says this node is S, the cycle start.
return NoneThe first loop ended without a meeting: no cycle, so no start.

8Dry run

List 1 → 2 → 3 → 4 → 5 → 6 → back to 3 (a = 2, K = 4).

stepphasepointerswhat happensanswer so far
01slow = 1, fast = 1start (no compare yet)—
11slow = 2, fast = 3fast went 1→2→3not met
21slow = 3, fast = 5slow enters the loop at Snot met
31slow = 4, fast = 3fast went 5→6→3 (wrapped)not met
41slow = 5, fast = 5fast went 3→4→5met at M = 5
52ptr = 1, slow = 5ptr reset to head; 1 ≠ 5 → both step—
62ptr = 2, slow = 62 ≠ 6 → both step—
72ptr = 3, slow = 3equal → stopreturn node 3
end of phase 1 (step 4):
[1] → [2] → [3] → [4] → [5] → [6]
             ↑             ↑     │
             │       slow, fast  │
             └───────────────────┘

start of phase 2 (step 5):
[1] → [2] → [3] → [4] → [5] → [6]
 ↑           ↑             ↑     │
ptr          │           slow    │
             └───────────────────┘

end of phase 2 (step 7):
[1] → [2] → [3] → [4] → [5] → [6]
             ↑                   │
         ptr, slow               │
             └───────────────────┘   → answer: node 3

The other examples

9Complexity & remember

The teacher's interview tip: remember the proof, not just the code. If you write "reset to head and move both" without explaining a + b = nK, it looks memorised.

Remember Cycle IIPhase 1: slow 1, fast 2 until they meet (M). Phase 2: ptr = head, both move 1 until equal → that's the start. Why: 2(a + b) = a + b + nK ⇒ a = nK − b, so head→S equals M→S (plus whole laps).

Part B · Revision page

Cycle I (LC 141)Cycle II (LC 142)
asksis there a cycle?where does it start?
phase 1slow 1 step, fast 2 steps, while fast and fast.next
when they meetreturn Truestart phase 2 (ptr = head, both speed 1)
no cyclereturn Falsereturn None
time / spaceO(n) / O(1)O(n) / O(1)
symbolmeaningin the example 1→…→6→3
ahead → cycle start S2
bS → meeting point M2
cM → S (rest of loop)2
Kloop length = b + c4
slow / fast distancea + b / a + b + nK4 / 8 (n = 1)
If you remember only 5 lines 1. Phase 1 is exactly Cycle I: slow 1, fast 2, meet → cycle exists.
2. The meeting point is not the start (in general).
3. Phase 2: one pointer at head, one at the meeting point, both speed 1.
4. They meet at the start because a = nK − b (head→S = M→S plus whole laps).
5. No meeting in phase 1 → return None. O(n) time, O(1) space.
Mistakes to avoid ✗ returning the phase-1 meeting node as the answer
✗ moving fast 2 steps in phase 2 (both must move 1)
✗ moving before checking in phase 2 (breaks a cycle that starts at head)
✗ comparing slow and fast before the first move in phase 1
✗ comparing values instead of nodes (is checks the same box)
bonus: the hash set version (O(n) space), for comparison
class Solution:
    def detectCycle(self, head):
        seen = set()
        curr = head
        while curr is not None:
            if curr in seen:        # first node met twice = cycle start
                return curr
            seen.add(curr)
            curr = curr.next
        return None
test it yourself (paste under either solution above)
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

def build(values, pos=-1):
    """Build a list; if pos >= 0, the last node links back to the node at index pos."""
    nodes = [ListNode(v) for v in values]
    for x, y in zip(nodes, nodes[1:]):
        x.next = y
    if pos >= 0 and nodes:
        nodes[-1].next = nodes[pos]
    return nodes[0] if nodes else None

s = Solution()
print(s.detectCycle(build([1, 2, 3, 4, 5, 6], 2)).val)   # 3
print(s.detectCycle(build([3, 2, 0, -4], 1)).val)        # 2
print(s.detectCycle(build([1, 2], 0)).val)               # 1
print(s.detectCycle(build([1])))                         # None
print(s.detectCycle(None))                               # None

Based on this video: Linked List Cycle II | Fast and Slow Pointer with proof