Given the head of a linked list, return the node where the cycle begins. If there is no cycle, return null.
A cycle exists if there is a node in the list that can be reached again by continuously following the next pointer.
Do not modify the linked list.
This problem extends Floyd's algorithm to not just detect a cycle, but find where it begins.
Phase 1: Detect if cycle exists
Phase 2: Find cycle entrance
Let's say:
L = distance from head to cycle entranceC = cycle lengthL + a distance (where a is distance into cycle)Since fast travels twice as fast:
L + a + nC (for some number of cycles n)L + a + nC = 2(L + a)L = nC - aThis means the distance from head to entrance equals the distance from meeting point to entrance!
For list: 3 → 2 → 0 → -4 → (back to 2)
Phase 1: Detect cycle
Head
↓
3 → 2 → 0 → -4
↑_________|
Slow and fast meet at node -4
Phase 2: Find entrance
ptr1 ptr2
↓ ↓
3 → 2 → 0 → -4
↑_________|
Move both 1 step at a time...
They meet at node 2 (the entrance!)
1/**
2 * Linked List Cycle II - Floyd's Cycle Detection Algorithm (Two-Phase)
3 *
4 * Time Complexity: O(n)
5 * Space Complexity: O(1)
6 */
7
8class ListNode {
9 int val;
10 ListNode next;
11 ListNode(int x) {
12 val = x;
13 next = null;
14 }
15}
16
17public class Solution {
18 public ListNode detectCycle(ListNode head) {
19 // Edge case: empty list or single node without cycle
20 if (head == null || head.next == null) {
21 return null;
22 }
23
24 // Phase 1: Detect if cycle exists using Floyd's algorithm
25 ListNode slow = head;
26 ListNode fast = head;
27
28 while (fast != null && fast.next != null) {
29 slow = slow.next;
30 fast = fast.next.next;
31
32 // If they meet, cycle exists
33 if (slow == fast) {
34 // Phase 2: Find cycle entrance
35 // Reset one pointer to head
36 slow = head;
37
38 // Move both pointers one step at a time
39 // They will meet at the cycle entrance
40 while (slow != fast) {
41 slow = slow.next;
42 fast = fast.next;
43 }
44
45 // Return the entrance node
46 return slow;
47 }
48 }
49
50 // Fast reached end, no cycle
51 return null;
52 }
53}
54
55// Alternative: Hash Set Approach
56class Solution2 {
57 public ListNode detectCycle(ListNode head) {
58 Set<ListNode> visited = new HashSet<>();
59 ListNode current = head;
60
61 while (current != null) {
62 // If we've seen this node before, it's the entrance
63 if (visited.contains(current)) {
64 return current;
65 }
66
67 // Mark node as visited
68 visited.add(current);
69 current = current.next;
70 }
71
72 // No cycle found
73 return null;
74 }
75}
76