Linked List Cycle
Description:
Given head, the head of a linked list, determine if the linked list has a cycle in it.
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.
Return true if there is a cycle in the linked list. Otherwise, return false.
Example 1:
Input: head = [3,2,0,-4], pos = 1
Output: true
Explanation: There is a cycle in the linked list, where the tail connects to the 1st node (0-indexed).
Example 2:
Input: head = [1,2], pos = 0
Output: true
Explanation: There is a cycle in the linked list, where the tail connects to the 0th node.
Example 3:
Input: head = [1], pos = -1
Output: false
Explanation: There is no cycle in the linked list.
Approaches:
1. Floyd's Cycle-Finding Algorithm (Tortoise and Hare)
The most optimal way to detect a cycle in a linked list without using extra memory is the Two Pointer technique, specifically Floyd's Cycle-Finding Algorithm.
We use two pointers moving at different speeds:
- A slow pointer (the tortoise) that moves one step at a time.
- A fast pointer (the hare) that moves two steps at a time.
- Initialize: Start both the
slowandfastpointers at theheadof the linked list. - Traverse: Loop through the list. In each iteration, move the
slowpointer by one node and thefastpointer by two nodes. - Check for Cycle: - If there is no cycle, the
fastpointer will eventually reach the end of the list (i.e.,fastorfast.nextbecomesnull). In this case, we returnfalse.- If there is a cycle, the
fastpointer will loop around and eventually "lap" theslowpointer. Ifslowandfastever point to the exact same node, a cycle exists, and we returntrue.
- If there is a cycle, the
Complexity
- Time Complexity: where is the number of nodes in the linked list. In the worst case, if there is a cycle, the fast pointer will catch the slow pointer in less than iterations. If there is no cycle, the fast pointer reaches the end in iterations.
- Space Complexity: . We only use two pointers, regardless of the size of the linked list.
Solutions:
C++
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(nullptr) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode *slow = head;
ListNode *fast = head;
while (fast != nullptr && fast->next != nullptr) {
slow = slow->next;
fast = fast->next->next;
if (slow == fast) {
return true;
}
}
return false;
}
};
Java
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
return true;
}
}
return false;
}
}
Python
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
from typing import Optional
class Solution:
def hasCycle(self, head: Optional['ListNode']) -> bool:
slow = head
fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
return True
return False
JavaScript
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @return {boolean}
*/
var hasCycle = function(head) {
let slow = head;
let fast = head;
while (fast !== null && fast.next !== null) {
slow = slow.next;
fast = fast.next.next;
if (slow === fast) {
return true;
}
}
return false;
};
Completed working through this block? Sync progress to workspace.