Linked List Cycle II

Updated on 03 June, 2025
Linked List Cycle II header image

Problem Statement

The task at hand revolves around identifying a cycle within a linked list, and more specifically, pinpointing the first node where this cycle begins. A cycle in a linked list implies that one or more nodes are revisited, creating a loop-like structure. This occurs when a node's 'next' pointer points to a previous node in the list, subsequently causing an infinite loop during traversal. It's crucial to note that the point where the tail node connects to another node (indicated by the position pos) is central to determining the cycle's start. However, this index pos isn't available as input; rather, it's a condition to be derived based on the list's structure. The operational constraints ensure that the list does not get modified during the cycle detection process.

Examples

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.

Approach and Intuition

Detecting the Cycle

  • Firstly, determining whether a cycle exists within the linked list is essential. The Floyd's Tortoise and Hare algorithm, known for its efficient cycle detection capacity, is apt for this task.
  1. Initialize two pointers, slow and fast. Both start at the head of the linked list.
  2. Progress slow by one step and fast by two steps iteratively.
  3. If a cycle exists, slow and fast will meet at some point within the loop. If fast reaches the end of the list (null), it concludes the absence of a cycle.

Locating the Start of the Cycle

  • Post cycle detection, the next step is to locate the node where the cycle begins. The intersection point where slow and fast met can be utilized to determine this.
  1. After the intersection is found, reinitialize one pointer to the head of the list while keeping the other at the intersection.
  2. Move both pointers one step at a time.
  3. The point at which they meet again represents the start of the cycle.

Understanding with Examples

  • Take example 1, where head = [3,2,0,-4] and pos = 1. Following the described algorithm:

  • Assuming pointers start at the head (value 3), the slow would traverse 3 -> 2 -> 0 while fast would move 3 -> 0 -> 2 -> 0 and so forth. They eventually meet at '2', pointing to the existence of a cycle.

  1. To pinpoint the cycle's start, reset the slow to the head and start moving both slow and fast one step at a time. They will meet again at 2, confirming it as the start of the cycle.

Conclusion

  • Applying this methodology guarantees the detection of cycles and the exact node of commencement in an O(N) time complexity, making it optimal for large lists within provided constraints. By understanding the movement of pointers and their intersection, the beginning of the loop can be conclusively determined, respecting the list's integrity by not altering it throughout the process.

Solutions

  • C++
  • Java
  • C
  • JavaScript
  • Python
cpp
class Solution {
public:
    ListNode* findCycleEntry(ListNode* head) {
        ListNode* slow = head;
        ListNode* fast = head;

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

            if (slow == fast) {
                break;
            }
        }

        if (!fast || !fast->next) {
            return nullptr;
        }

        fast = head;

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

        return slow;
    }
};

The C++ solution provided tackles the problem of identifying the start node of a cycle in a linked list. The approach uses a two-pointer strategy known as Floyd's Tortoise and Hare algorithm:

  • Start both pointers, slow and fast, from the head of the linked list. Move slow by one step and fast by two steps through the list.
  • Continue the process until slow and fast meet, indicating a cycle presence. If fast or its next pointer becomes null, there is no cycle, and return nullptr.
  • Post detection, reset fast to the head of the list and proceed to move both slow and fast one step at a time.
  • The node where slow and fast meet again is the entrance to the loop.

The efficiency of this method stems from its ability to detect and locate the cycle's start without additional space requirements, maintaining an O(n) time complexity and O(1) space complexity. This way, implement the linked list cycle detection and positioning efficiently.

java
public class Solution {
    public ListNode findCycleStart(ListNode head) {
        // Pointers for cycle detection
        ListNode slow = head;
        ListNode fast = head;

        // Traverse to find if there is a cycle
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;

            // Check for cycle
            if (slow == fast) {
                break;
            }
        }

        // Handle no cycle case
        if (fast == null || fast.next == null) {
            return null;
        }

        // Reset pointer to head for cycle entry point detection
        fast = head;

        // Move both pointers at the same rate to find entry point
        while (slow != fast) {
            slow = slow.next;
            fast = fast.next;
        }

        // Node where the cycle starts
        return slow;
    }
}

The provided Java solution implements a function to detect the starting node of a cycle in a linked list. It utilizes the Floyd’s Cycle Detection algorithm, also known as the "hare and tortoise" approach. This algorithm leverages two pointers, slow and fast, which move at different speeds through the linked list.

  • Initiate both slow and fast pointers at the head of the linked list.
  • Iterate through the list. Move slow pointer by one node and fast pointer by two nodes simultaneously. If these pointers meet, a cycle is detected.
  • If fast or fast.next becomes null, it implies that the list does not contain a cycle. Return null in such case.
  • Upon cycle detection, position the fast pointer back to the head of the linked list while keeping the slow pointer at the meeting point.
  • Move both slow and fast pointers one step at a time. The node where they meet again is the start of the cycle.

This solution efficiently detects the entry point of a cycle in a linked list while maintaining a linear time complexity. It doesn't require additional memory for tracking visited nodes, making it optimal for environments with limited memory resources.

c
struct ListNode *findCycle(struct ListNode *start) {
    struct ListNode *slow = start;
    struct ListNode *fast = start;

    if (start == NULL || start->next == NULL) {
        return NULL;
    }
  
    do {
        slow = slow->next;
        fast = fast->next->next;
    } while (fast != NULL && fast->next != NULL && slow != fast);
  
    if (fast == NULL || fast->next == NULL) {
        return NULL;
    }
  
    fast = start;
  
    while (slow != fast) {
        slow = slow->next;
        fast = fast->next;
    }
  
    return slow;
}

This article provides a clear insight into a C function designed to identify the starting point of a cycle within a linked list if one exists. The function named findCycle accepts a pointer to the start of a linked list and returns the node where the cycle begins, using Floyd's Tortoise and Hare algorithm approach.

  • The function first initializes two pointers, slow and fast, both pointing to the start of the linked list.
  • It checks whether the list is empty or has only one node; if either condition is true, it returns NULL as no cycle could exist.
  • The function then enters a loop where the slow pointer advances by one node, and the fast pointer advances by two nodes. This continues until either:
    • The fast pointer encounters a NULL, indicating there is no cycle.
    • The slow and fast pointers meet, indicating a cycle.
  • If no cycle is found and the fast pointer reaches the end of the list, the function returns NULL.
  • If a cycle is detected, to find the start of this cycle, fast is reset to the start of the list and both fast and slow now move one node at a time.
  • The point at which they meet again is the starting node of the cycle, and this node is then returned.

The implementation ensures that the approach is efficient and comprehensible, utilizing a two-pointer technique to effectively determine the presence and origin of a cycle within a linked list, thereby solving the problem in linear time with constant space complexity.

js
var findCycleStart = function (head) {
    let slow = head, fast = head;
    while (fast && fast.next) {
        slow = slow.next;
        fast = fast.next.next;
        if (slow === fast) {
            break;
        }
    }
    if (!fast || !fast.next) {
        return null;
    }
    fast = head;
    while (slow !== fast) {
        slow = slow.next;
        fast = fast.next;
    }
    return slow;
};

This article provides a solution to detect the start of a cycle in a linked list using JavaScript. The provided solution uses the two-pointer technique, specifically the Floyd's cycle-finding algorithm.

  • Begin with two pointers, slow and fast, both initialized at the head of the linked list.
  • Progress slow by one node and fast by two nodes in each step of a loop. Continue looping as long as fast and its next node are not null.
  • If both pointers meet (slow === fast), a cycle exists. Break out of the loop to find the cycle's start.
  • If no cycle is detected (either fast or fast.next is null), return null indicating no cycle.
  • Reposition fast at the head of the list and move both slow and fast at the same pace (one step at a time).
  • The node at which slow and fast meet again is the start of the cycle. Return this node as the result.

By following these steps, efficiently determine the entry point of a cycle in a linked list, if one exists, using JavaScript.

python
class Solution:
    def findCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
        slow_pointer = head
        fast_pointer = head

        while fast_pointer and fast_pointer.next:
            slow_pointer = slow_pointer.next
            fast_pointer = fast_pointer.next.next

            if slow_pointer == fast_pointer:
                break

        if not fast_pointer or not fast_pointer.next:
            return None

        fast_pointer = head

        while slow_pointer != fast_pointer:
            slow_pointer = slow_pointer.next
            fast_pointer = fast_pointer.next

        return slow_pointer

This solution detects the presence of a cycle within a linked list and returns the node where the cycle begins using the Turtle and Hare (Floyd's Cycle Detection Algorithm).

The algorithm works in two primary phases:

  1. Detect if a cycle exists:

    • Initialize two pointers, slow_pointer and fast_pointer, both starting at the head of the linked list.
    • Move slow_pointer one step at a time and fast_pointer two steps at a time.
    • If a cycle exists, slow_pointer and fast_pointer will eventually meet inside the cycle.
  2. Find the entry point of the cycle:

    • If a cycle is detected (from the previous step), reset fast_pointer back to the head of the linked list.
    • Move both slow_pointer and fast_pointer one step at a time.
    • The node where they meet this time is the starting node of the cycle.

If no cycle is detected in the first phase, return None indicating there is no cycle in the list.

The Python code provided effectively handles the identification and retrieving of the cycle's initial node efficiently, addressing the problem as described.

Comments

No comments yet.