
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 <= 105posis-1or 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.
- Initialize two pointers,
slowandfast. Both start at the head of the linked list. - Progress
slowby one step andfastby two steps iteratively. - If a cycle exists,
slowandfastwill meet at some point within the loop. Iffastreaches 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
slowandfastmet can be utilized to determine this.
- After the intersection is found, reinitialize one pointer to the head of the list while keeping the other at the intersection.
- Move both pointers one step at a time.
- 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]andpos = 1. Following the described algorithm:Assuming pointers start at the head (value 3), the
slowwould traverse3 -> 2 -> 0whilefastwould move3 -> 0 -> 2 -> 0and so forth. They eventually meet at '2', pointing to the existence of a cycle.
- To pinpoint the cycle's start, reset the
slowto the head and start moving bothslowandfastone step at a time. They will meet again at2, 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
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,
slowandfast, from the head of the linked list. Moveslowby one step andfastby two steps through the list. - Continue the process until
slowandfastmeet, indicating a cycle presence. Iffastor its next pointer becomes null, there is no cycle, and returnnullptr. - Post detection, reset
fastto the head of the list and proceed to move bothslowandfastone step at a time. - The node where
slowandfastmeet 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.
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
slowandfastpointers at the head of the linked list. - Iterate through the list. Move
slowpointer by one node andfastpointer by two nodes simultaneously. If these pointers meet, a cycle is detected. - If
fastorfast.nextbecomes null, it implies that the list does not contain a cycle. Return null in such case. - Upon cycle detection, position the
fastpointer back to the head of the linked list while keeping theslowpointer at the meeting point. - Move both
slowandfastpointers 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.
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,
slowandfast, 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
slowpointer advances by one node, and thefastpointer advances by two nodes. This continues until either:- The
fastpointer encounters a NULL, indicating there is no cycle. - The
slowandfastpointers meet, indicating a cycle.
- The
- If no cycle is found and the
fastpointer reaches the end of the list, the function returns NULL. - If a cycle is detected, to find the start of this cycle,
fastis reset to the start of the list and bothfastandslownow 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.
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,
slowandfast, both initialized at the head of the linked list. - Progress
slowby one node andfastby two nodes in each step of a loop. Continue looping as long asfastand 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
fastorfast.nextis null), returnnullindicating no cycle. - Reposition
fastat the head of the list and move bothslowandfastat the same pace (one step at a time). - The node at which
slowandfastmeet 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.
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:
Detect if a cycle exists:
- Initialize two pointers,
slow_pointerandfast_pointer, both starting at the head of the linked list. - Move
slow_pointerone step at a time andfast_pointertwo steps at a time. - If a cycle exists,
slow_pointerandfast_pointerwill eventually meet inside the cycle.
- Initialize two pointers,
Find the entry point of the cycle:
- If a cycle is detected (from the previous step), reset
fast_pointerback to the head of the linked list. - Move both
slow_pointerandfast_pointerone step at a time. - The node where they meet this time is the starting node of the cycle.
- If a cycle is detected (from the previous step), reset
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.