Cycle detection (Floyd’s tortoise and hare with 2 pointers)
The idea is that we utilize 2 pointers slow (tortoise) and fast (hare), where we move slow 1 step and move fast 2 steps in each iteration.
The observations:
- If there is no cycle in the list, the fast pointer will eventually reach the end and we can return false in this case.
- If there is a cycle, once slow entering the cycle, it will be like both slow and fast are running in the cycle. And because fast is just one step quicker - eventually it must be able to meet with slow.
So whether or not there is a cycle simply depends on observation 1
What if we want to find where the cycle starts?
The algorithm is:
- once `slow` and `fast` meet, moves `slow` back to head, `fast` stay at meeting point.
- then move one step for both `slow` and `fast` in each iteration.
- when they meet again, they are at the beginning of cycle.:thinking: Why?
:bulb: The math basics:
C ≡ 0 (mod C).
Let’s assume that there is a cycle in the linked list, say
- There are
Tnodes before cycle, andCnodes in the cycle. - Let’s mark the node’s indices as
[-T, ..., -1]for theTnodes before the cycle and[0, ..., C - 1]for theCnodes in the cycle.
T ____k H = head = node index -T
H--------X \ <- X = beginning of cycle = node index 0
^ | k = hitting point = node index k
\_____/ C = number of nodes in the cycleExplanation :one:
Say when meet at k
x: number of complete cyclefastpointer run when meetingy: number of complete cycleslowpointer run when meeting
Then
-
slowtookT + y * C + ksteps … (1) -
fasttookT + x * C + ksteps … (2) -
And because
f = 2s,f = 2 (T + yC + k)…(3) -
as (3) == (2), so
2T + 2yC + 2k = T + xC + k, e.g.T + k = (x - 2y) * C -
This implies
T + kis a multiple of C (cycle length). Thus we can write,T + k = zC,z = (x - 2y)being some integer. Or we say,T = zC - k. -
Say now, we move
slowpointer from head, andfastpointer stay at meeting pointk, and making both of them only travel 1 at a time -
Then when both
slowandfastmove additionalT = zC - kstepsslowshould be at0 + T = T, e.g. begin of cycle.- And
fastshould be atk + T = k + zC - k = zC ≡ 0 (mod C).
-
E.g. both of them travel to node X (index 0) and they meet again. And the meeting point is node index 0, the start of cycle!!
Explanation :two:
-
As
fastmove twice faster, whenslowmovest,fastmoves2t -
So after
Titerations,slowis at node 0. We assume at the same time,fastis at noder. -
:bulb: The key observation is, since after
Titerations,fastmust have traveled2T, while the firstTare used in the non-cycle portion. We know thatfastmust travel within the cycle forTsteps at this moment. This implies thatr ≡ T (mod C) -
Say now, we move additional
C - riterations, what would happen?slowis at node0 + C - r = C - r, andfastat noder + 2(C - r) = 2C - r- And because
2C - r ≡ C - r (mod C), we know that at this moment,slowandfastmeets.
-
So right after they meet (at node
C - r), if we moveslowback to front, and changefastto move 1 step as well, what would happen after additionalTsteps?slowwill be at node 0 again.fastwill be atC - r + T ≡ C - r + r ≡ 0 (mod C)(because (Eq.1))- E.g. they are both at node 0 now!!!
- E.g. once they meet again, we find the starting point of cycle!!!