Skip to content

LC142. Linked List Cycle II

Problem Description

LeetCode Problem 142: Given the head of 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 (0-indexed). It is -1 if there is no cycle. Note that pos is not passed as a parameter.

Do not modify the linked list.

Clarification

Assumption

Solution

Approach - Slow/fast pointers

The problem can be solved by using the Floyd’s cycle detection method to find the meet point, which consists of two phases:

  • Phase I: Detect a cycle and find the meeting point if there is a cycle Use a slow pointer that moves 1 step a time and a fast pointer that moves 2 steps a time to detect a cycle and find the meeting point if there is a cycle. Follow the approach in LC141 Linked List Cycle
  • Phase II: If there is a cycle, return the entry location of the cycle For analysis, define the following notations:

    • \(l_1\): the distance (i.e., number of nodes) between the head and the entry point of the cycle
    • \(l_2\): the distance (i.e., number of nodes) between the entry point and the meeting point in the cycle
    • \(c\): length of the cycle
    • \(n\): number of cycles the fast pointer moves (\(n >= 1\))
    flowchart LR
        head((H))
        entry((E))
        meet(((M)))
    
        head --l1--> entry
        entry --l2--> meet
        meet --c - l2--> entry

    When slow and fast pointers meet,

    • the travel distance of the slow pointer is \(l_1 + l_2\)
    • the travel distance of the fast pointer is \(l_1 + l_2 + nc\)
    • since the fast pointer moves twice fast as the slow pointer, the travel distance of the fast pointer is twice as the slow pointer,
    \[ \begin{eqnarray} 2(l_1 + l_2) &=& l_1 + l_2 + nc \\ l_1 + l_2 &=& nc \\ l_1 &=& (n−1)c+(c−l_2) \end{eqnarray} \]

    The above equation implies that the distance, \(l_1\), between the head and entry point of the cycle is equal to the distance, \(c - l_2\), between the meeting point and entry point along the direction of the forward movement. So we can have two pointers with the same speed (1 step a time). One starts from the head and the other starts from the meeting points. When these two pointers meet, the meeting node is where the cycle begins.

class Solution:
    def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
        if head is None or head.next is None:
            return None

        slow = head
        fast = head
        entry = head

        while fast.next and fast.next.next:
            slow = slow.next
            fast = fast.next.next

            if slow == fast:  # there is a cycle
                while slow != entry:  # find entry location when slow == entry
                    slow = slow.next
                    entry = entry.next

                return entry
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if (head == nullptr || head->next == nullptr) return nullptr;

        ListNode* slow = head;
        ListNode* fast = head;
        ListNode* entry = head;

        while (fast != nullptr && fast->next != nullptr) {
            slow = slow->next;
            fast = fast->next->next;

            // Detect a cycle and find the entry point
            if (slow == fast) {
                while (entry != slow) {
                    entry = entry->next;
                    slow = slow->next;
                }

                return entry;
            }
        }

        return nullptr;
    }
};

Complexity Analysis

  • Time complexity: \(O(n)\)
    Denotes n as the total number of nodes in the linked list. For time complexity, analyze the following two cases separately:
    – List has no cycle: The fast pointer reaches the end first. Since it moves two steps a time, the time complexity is O(n/2).
    – List has a cycle: For Phase I, it takes l1 + l2 iterations to find the meet point. For Phase II, it takes c − l2 iterations to find the entry point of the cycle. So the total number of iterations is l1 + l2 + c − l2 = n.
  • Space complexity: \(O(1)\)
    Only use several pointers.

Test