Question
Given a linked list, determine the entry point of the loop. The entry point is essentially the intersection point of the line and the circle.
Similar Questions
- Easy - 141. Linked List Cycle
- Medium - 287. Find the Duplicate Number
Solution - HashSet
Traverse the linked list, and save the traversed nodes with HashSet
. If we encounter the previous node during the traversal, it means that this node is the entry point we want to find. If it reaches null
, there is no loop.
1 | public ListNode detectCycle(ListNode head) { |
Solution - Two Pointers
Two pointers is one of the most commonly used method when solving linked list problems.
The principle of fast and slow pointers is easy to understand. Imagine a round track where two people are running. If one person runs fast and one person runs slowly, then no matter where they start from, the two will definitely meet during the run.
So here we use two pointers fast and slow. Fast takes two steps at a time, and slow takes one step at a time. If fast reaches null, there is no ring. If fast and slow meet, there is a loop.
But for this problem, we need to find the entry point, and the point where the fast
and slow
pointers meet may not be the entry point, but a certain point in the loop, so some mathematical derivation is needed here. Referenced from: https://leetcode.com/problems/linked-list-cycle-ii/discuss/44793/O(n)-solution-by-using-two-pointers-without-change-anything
The distance from the head
to the entry point
is set to x
, the distance from the entry point
to the meeting point
is set to y
, and the length of the loop is set to n
.
Assuming the distance traveled by the slow
pointer is t
, then the fast
pointer must travel twice the distance of the slow
pointer, which is 2t
.
The slow
pointer starts from the head
and walks the distance of x
to reach the entry point
, and then possibly walks k1
circles, then returns to the entry point
again, and then walks the distance of y
to reach the meeting point
and meet the fast
pointer.
1 | t = x + k1 * n + y |
The same applies to the fast
pointer. The fast
pointer starts from the head
and walks a distance of x
to reach the entry point
, and then possibly walks k2
circle, then returns to the entry point
again, and then walks a distance of y
to reach the meeting point
and meet the slow
pointer.
1 | 2t = x + k2 * n + y |
Take the difference by the two equations above, you can get
1 | t = (k2 - k1) * n |
Let k = k2-k1
, then t = k * n
.
Substitute t = k * n
into the first expression t = x + k1 * n + y
.
1 | k * n = x + k1 * n + y |
Shift term, x = (k-k1) * n-y
Take a combination of n
and y
, get:
1 | x = (k-k1-1) * n + (n-y) |
The left part of the equation means: reach the entry point
from head
.
The right part of the equation means: n-y
is the distance from the meeting point
to the entry point
, (k-k1-1) * n
is to turn (k-k1-1)
circle.
Combining left and right part: walking from the meeting point
to the entry point
, then turning (k-k1-1)
circle and returning to the entry point
again is exactly the same time from head
to the entry point
.
So for the code, we only need the meet
pointer to start from the meeting point
, and let the head
pointer also start. The position where the head
pointer meets the meet pointer
is the entry point
.
1 | public ListNode detectCycle(ListNode head) { |