Linked list cycle II

LeetCode problem 142. Linked List Cycle II

## Problem description

Given a linked list, return the node where the cycle begins. If there is no cycle, return `null`.

There is a cycle in a linked list if there is some node in the list that can be reached again by continuously following the `next` pointer. Internally, `pos` is used to denote the index of the node that tail's `next` pointer is connected to. **Note that `pos` is not passed as a parameter**.

**Notice** that you **should not modify** the linked list.

Example 1

* **Input:** head = [3,2,0,-4], pos = 1
* **Output:** tail connects to node index 1
* **Explanation:** There is a cycle in the linked list, where tail connects to the second node.

Example 2

* **Input:** head = [1,2], pos = 0
* **Output:** tail connects to node index 0
* **Explanation:** There is a cycle in the linked list, where tail connects to the first node.

Example 3

* **Input:** head = [1], pos = -1
* **Output:** no cycle
* **Explanation:** There is no cycle in the linked list.

Constraints
* The number of the nodes in the list is in the range `[0, 104]`.
* `-105 <= Node.val <= 105`
* `pos` is `-1` or a **valid index** in the linked-list.

Follow up
Can you solve it using **O(1) (i.e. constant) memory**?
## Analysis

One approach we can use to keep **O(1) memory** is to use the **Floyd's loop detection algorithm**.

1. Check whether we do have a loop using the **slow-fast pointers** method in the Linked list cycle problem.
	* If a loop is not found, then we do not need to go through further steps.
2. If a loop is found, then we position the slow pointer back to the head of the loop, and keep the fast pointer where the two pointers have met up with each other.
3. Move the slow pointer and the fast pointer one step each time.
4. The node at which the two pointers meet again is the start of the loop.

### Proof of correctness

Suppose that we have *m* steps from the head of the link list to the start of the loop, and *n* steps in the cycle.

First we use a **slow pointer** and a **fast pointer** to detect whether there is a loop. Stop the iteration when the two pointers meet up. (See Linked list cycle#Analysis)

* The slow pointer moves forward by 1 step per iteration.
* The fast pointer moves forward by 2 steps per iteration.

If we have detected a cycle, one thing to note is that the slow pointer must have travelled less than the full cycle since its first entry into the loop.

* This is because in the worst case, the fast pointer is just at the node in front of the slow pointer. The chasing distance is *n-1*. For the slow pointer, the number of steps from entering the loop from being caught up by the fast pointer ≤ *(n-1)/(2-1) = n-1*. Then the slow pointer will be caught up by the fast pointer right before it reaches the start of the loop again.

Let *x* be the offset of the meeting point of the two pointers from the beginning of the cycle. *x* can be calculated as follows:

1. Let *k* be the offset of the fast pointer from the beginning of the cycle. Since the fast pointer is *m* steps ahead of the slow pointer, we have *k* = *m* mod *n*. So *k < n*.
2. Now the chasing distance for the fast pointer is *n - k*.
3. Then *x* equals to the number of steps the slow pointer has traveled from entering the cycle to being caught by the fast pointer. Then ***x* = *(n - k) / (2 - 1)* = *n - k***.

At this moment, it is also apparent that the distance from the meeting point to reaching the start of the cycle the next time (by going forward only) is *n - x = n - (n - k) = k*. In addition, we have *k* = *m* mod *n*. This means that from the meeting point, going *k* steps forward is equivalent to going *m* steps forward, which will both end up at the start of the cycle.

So the next steps will be:

1. Put the slow pointer back to the head.
2. Keep the fast pointer at the meeting point of both pointers.
3. Move both the slow pointer and the fast pointer one step per iteration, until they meet up again.
4. The new meeting point is the start of the cycle.

### Complexity analysis

#### Time complexity

1. In the first phase of detecting loop, sending the slow pointer from head to the meeting point takes *m + (m* mod *n) < m + n* steps.
2. In the second phase of locating the start of the loop, sending the slow pointer from head to the start of loop takes *m* steps.

So the total time complexity is **O(*m + n*)**, where *m* is the number of steps outside the loop, and *n* is the number of steps inside the loop. In other words, the time complexity is *linearly* related to the total number of nodes.

#### Space complexity

Since we only used the slow pointer and the fast pointer, without allocating extra objects, the space complexity is **O(1)**.

## Solutions

### C++ solution

```
/\*\*
 \* Definition for singly-linked list.
 \* struct ListNode {
 \* int val;
 \* ListNode \*next;
 \* ListNode(int x) : val(x), next(NULL) {}
 \* };
 \*/
class Solution {
private:
 // find the node at which the fast pointer catches up the slow pointer
 // if fast pointer reaches nullptr (no cycle found), return nullptr
 static ListNode\* catchUp(ListNode\* head) {
 ListNode \*slow = head, \*fast = head;
 while (fast != nullptr) {
 fast = fast->next;
 if (fast != nullptr) {
 fast = fast->next;
 }
 if (fast != nullptr) {
 slow = slow->next;
 }
 if (slow == fast) {
 break;
 }
 }
 return fast;
 }

public:
 ListNode\* detectCycle(ListNode\* head) {
 // corner cases
 if ((head == nullptr) || (head->next == nullptr)) {
 return nullptr;
 }

 // find meeting point for detecting cycle
 ListNode \*fast = catchUp(head);
 if (fast == nullptr) {
 return nullptr;
 }

 // get the start of cycle
 ListNode \*slow = head;
 while (slow != fast) {
 slow = slow->next;
 fast = fast->next;
 }
 return slow;
 }
};

```

### Java solution

```
/\*\*
 \* Definition for singly-linked list.
 \* class ListNode {
 \* int val;
 \* ListNode next;
 \* ListNode(int x) {
 \* val = x;
 \* next = null;
 \* }
 \* }
 \*/
public class Solution {
 // find the node at which the fast pointer catches up the slow pointer
 // if fast pointer reaches null (no cycle found), return null
 private static ListNode catchUp(ListNode head) {
 ListNode slow = head, fast = head;
 while (fast != null) {
 fast = fast.next;
 if (fast != null) {
 fast = fast.next;
 }
 if (slow != null) {
 slow = slow.next;
 }
 if (slow == fast) {
 break;
 }
 }
 return fast;
 }

 public ListNode detectCycle(ListNode head) {
 // corner cases
 if ((head == null) || (head.next == null)) {
 return null;
 }

 ListNode fast = catchUp(head);
 if (fast == null) {
 return null;
 }

 ListNode slow = head;
 while (slow != fast) {
 slow = slow.next;
 fast = fast.next;
 }
 return slow;
 }
}

```

## References

1. ↑ Find first node of loop in a linked list (Archive)

## External links

* Find first node of loop in a linked list (Archive)
* Detect loop in a linked list using **Floyd’s Cycle-Finding Algorithm** (Archive)