Topics › Linked List › Medium Problems of LL
Find the starting point in LL
LeetCode ↗ Java source ↗ Edit this article ↗
Jump to code:
Problem
Given the head of a singly linked list, return the node where its loop begins, or null if the list has no loop. The loop starts at the first node that you would visit twice when following next pointers from the head. Do not modify the list.
A list with a loop looks like the Greek letter rho: a straight “tail” of L nodes that leads into a circle of C nodes. The answer is the node where the tail joins the circle. When L = 0, the head itself is on the circle and is the answer.
Constraints: up to 10^4 nodes in the LeetCode version. The follow-up asks for O(1) extra memory.
static class ListNode {
int val;
ListNode next;
ListNode(int val) { this.val = val; }
}
Example 1
3 -> 2 -> 0 -> -4
^ |
+----------+
answer = the node holding 2 // the tail is just [3], then the circle 2 -> 0 -> -4 -> 2
Example 2
1 -> 2 -> 3 -> null
answer = null // no loop
Approach 1: Brute force, the first node seen twice
Intuition. Walk the list and remember every node in a hash set. The walk passes the L tail nodes once each, then enters the circle at its starting node s and goes around: s, then the other C - 1 circle nodes, then s again. Every node before that second visit of s was new, so s is the very first node we find already in the set. That makes “first repeated node” and “start of the loop” the same thing.
Algorithm.
- Create an empty
HashSet<ListNode>. - Walk the list. If adding the current node fails (it is already in the set), return it.
- If the walk reaches
null, returnnull.
static ListNode hashing(ListNode head) {
Set<ListNode> visited = new HashSet<>();
for (ListNode cur = head; cur != null; cur = cur.next) {
if (!visited.add(cur)) return cur; // the walk re-enters the loop exactly at its start
}
return null;
}
Complexity. Time O(n): the walk takes L + C + 1 steps at most, and L + C = n. Space O(n) for the set.
This is simple and correct, but it stores every node. The follow-up asks us to drop that memory.
Approach 2: Optimal, Floyd’s algorithm with a second phase
Intuition. Phase 1 is plain loop detection: slow moves one node per step, fast moves two. If fast reaches null, there is no loop. Otherwise they meet somewhere on the circle (the gap between them shrinks by exactly one per step once both are on it, so it must hit zero).
Phase 2 finds the entrance. Put a new pointer entry on the head and move entry and slow one step at a time. They meet exactly at the start of the loop. Here is why.
Number the steps of a walk from the head: after s steps you are on node p(s). Tail nodes are visited once, so for s < L all p(s) are distinct. On the circle, p(s) = p(s') for s, s' ≥ L exactly when s - s' is a multiple of C.
- Suppose
slowandfastmeet aftertsteps. Thenp(t) = p(2t). They cannot meet in the tail (tail nodes are never revisited), sot ≥ L, and therefore2t - t = tis a multiple ofC. - In phase 2, after
Lmore stepsslowhas madet + Lsteps in total. Sincetis a multiple ofC,p(t + L) = p(L), the start of the loop. - After
Lstepsentryis atp(L)too. Before that,entryis still in the tail whileslowis on the circle, so they cannot meet earlier.
So the two pointers meet for the first time exactly at the loop’s start, after L steps, without ever knowing L or C.
Algorithm.
slow = fast = head. Whilefastandfast.nextare notnull, moveslowby one andfastby two.- If
slow == fast, setentry = headand moveentryandslowone step at a time until they are equal. Returnentry. - If the first loop ends, return
null.
static ListNode optimal(ListNode head) {
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) { // inside the loop; now locate its entrance
ListNode entry = head;
while (entry != slow) { // head and meeting point are equally far from the start
entry = entry.next;
slow = slow.next;
}
return entry;
}
}
return null; // fast reached the end: no loop
}
Dry run on Example 1. Nodes n0 = 3, n1 = 2, n2 = 0, n3 = -4, with n3.next = n1. Here L = 1 and C = 3.
| phase | step | slow | fast / entry |
|---|---|---|---|
| 1 | 1 | n1 | fast n2 |
| 1 | 2 | n2 | fast n1 |
| 1 | 3 | n3 | fast n3, meet after t = 3 steps |
| 2 | 0 | n3 | entry n0 |
| 2 | 1 | n1 | entry n1, equal: return n1 |
The meeting happened after t = 3 steps, a multiple of C = 3, exactly as the argument predicts. Phase 2 needed L = 1 step.
Complexity. Time O(n): phase 1 ends within L + C steps of the slow pointer, and phase 2 takes L steps. Space O(1).
Edge cases and pitfalls
- No loop.
fastreachesnulland the method returnsnull. This includes the empty list and a single node without a self-loop. - Loop through the head (
L = 0).entrystarts equal to the meeting point, so phase 2 runs zero steps and returns the head. A single node pointing to itself is the smallest example. - Loop of length 1 at the end. The last node pointing to itself gives
C = 1; the proof still applies and the method returns the last node. The Java tests cover this with10^5nodes. - Moving
fastin phase 2. In the second phase both pointers move one step. Keepingfastat double speed breaks the argument. - Restarting the wrong pointer. You may restart either
sloworfastat the head, but the other one must stay at the meeting point. Restarting both, or starting phase 2 from a node other than the meeting point, gives a wrong answer. - Values are irrelevant. The tests include a list of equal values (
5 5 5 5 5) where only node identity tells the start apart. Always compare references. - Do not modify the list. Marking visited nodes or breaking links would also find the start, but the problem forbids changing the structure.
Related problems
- Detect a loop in LL is phase 1 on its own.
- Find the starting point in LL is the same problem in the A2Z sheet.
- Length of loop in LL counts
Cafter the meeting point instead of finding the entrance. - Find the Duplicate Number uses exactly this two-phase algorithm on an array whose values act as
nextpointers. - Find the intersection point of Y LL is another “walk equal distances so the pointers meet at a special node” argument.