Given the head of a singly linked list, determine whether the list contains a cycle.
A cycle exists if, while traversing the list through next pointers, you encounter a node that has already been visited instead of eventually reaching nullptr.
Examples:
Input: head: 1 -> 3 -> 4 -> 3 Output: true
Explanation: The last node of the linked list does not point to NULL; instead, it points to an earlier node in the list, creating a cycle.
[Naive Approach] Using HashSet - O(n) Time and O(n) Space
The idea is to insert the nodes in the Hashset while traversing and whenever a node is encountered that is already present in the hashset (which indicates there's a cycle (loop) in the list) then return true. If the node is NULL, represents the end of Linked List, return false as there is no loop.
C++
#include<iostream>#include<unordered_set>usingnamespacestd;classNode{public:intdata;Node*next;Node(intx){this->data=x;this->next=nullptr;}};booldetectLoop(Node*head){unordered_set<Node*>st;while(head!=nullptr){// if this node is already present// in hashmap it means there is a cycleif(st.find(head)!=st.end())returntrue;// if we are seeing the node for// the first time, insert it in hashst.insert(head);head=head->next;}returnfalse;}intmain(){Node*head=newNode(1);head->next=newNode(3);head->next->next=newNode(4);head->next->next->next=head->next;if(detectLoop(head))cout<<"true";elsecout<<"false";return0;}
Java
importjava.util.HashSet;classNode{intdata;Nodenext;Node(intx){this.data=x;this.next=null;}}classGfG{staticbooleandetectLoop(Nodehead){HashSet<Node>st=newHashSet<>();while(head!=null){// if this node is already present// in hashmap it means there is a cycleif(st.contains(head))returntrue;// if we are seeing the node for// the first time, insert it in hashst.add(head);head=head.next;}returnfalse;}publicstaticvoidmain(String[]args){Nodehead=newNode(1);head.next=newNode(3);head.next.next=newNode(4);head.next.next.next=head.next;if(detectLoop(head))System.out.println("true");elseSystem.out.println("false");}}
Python
classNode:def__init__(self,x):self.data=xself.next=NonedefdetectLoop(head):st=set()whileheadisnotNone:# if this node is already present# in hashmap it means there is a cycleifheadinst:returnTrue# if we are seeing the node for# the first time, insert it in hashst.add(head)head=head.nextreturnFalseif__name__=="__main__":head=Node(1)head.next=Node(3)head.next.next=Node(4)head.next.next.next=head.nextifdetectLoop(head):print("true")else:print("false")
C#
usingSystem;usingSystem.Collections.Generic;classNode{publicintdata;publicNodenext;publicNode(intx){this.data=x;this.next=null;}}classGfG{staticbooldetectLoop(Nodehead){HashSet<Node>st=newHashSet<Node>();while(head!=null){// if this node is already present// in hashmap it means there is a cycleif(st.Contains(head))returntrue;// if we are seeing the node for// the first time, insert it in hashst.Add(head);head=head.next;}returnfalse;}staticvoidMain(){Nodehead=newNode(1);head.next=newNode(3);head.next.next=newNode(4);head.next.next.next=head.next;if(detectLoop(head))Console.WriteLine("true");elseConsole.WriteLine("false");}}
JavaScript
classNode{constructor(x){this.data=x;this.next=null;}}functiondetectLoop(head){constst=newSet();while(head!==null){// if this node is already present// in hashmap it means there is a cycleif(st.has(head))returntrue;// if we are seeing the node for// the first time, insert it in hashst.add(head);head=head.next;}returnfalse;}// Driver Codelethead=newNode(1);head.next=newNode(3);head.next.next=newNode(4);head.next.next.next=head.next;if(detectLoop(head))console.log("true");elseconsole.log("false");
Output
true
[Expected Approach] Using Floyd's Cycle-Finding Algorithm
This idea is to use Floyd's Cycle-Finding Algorithm to find a loop in a linked list. It uses two pointers slow and fast, fast pointer move two steps ahead and slow will move one step ahead at a time.
Algorithm:
Traverse linked list using two pointers.
Move one pointer(slow) by one step ahead and another pointer(fast) by two steps ahead.
If these pointers meet at the same node then there is a loop. If pointers do not meet then the linked list doesn't have a loop.
Below is the illustration of above algorithm:
Why meeting is guaranteed if a cycle exists ?
Let: m = number of nodes before the cycle starts and c = length of the cycle (number of nodes in the loop)
When both pointers enter the cycle: At that point, the difference in steps between fast and slow increases by 1 each turn (because fast moves 1 step more than slow each iteration). This difference is taken modulo c because positions wrap around inside the cycle.
Mathematically:
If d is the difference in positions (mod c), then each iteration: d ≡ d + 1 (mod c)
Since 1 and c are coprime, adding 1 repeatedly cycles through all residues 0, 1, 2, …, c-1.
Thus, eventually d ≡ 0 → meaning both pointers are at the same node (meeting point).
#include<iostream>usingnamespacestd;classNode{public:intdata;Node*next;Node(intx){this->data=x;this->next=nullptr;}};booldetectLoop(Node*head){// Fast and slow pointers // initially points to the headNode*slow=head,*fast=head;// Loop that runs while fast and slow pointer are not// nullptr and not equalwhile(slow&&fast&&fast->next){slow=slow->next;fast=fast->next->next;// If fast and slow pointer points to the same node,// then the cycle is detectedif(slow==fast){returntrue;}}returnfalse;}intmain(){Node*head=newNode(1);head->next=newNode(3);head->next->next=newNode(4);head->next->next->next=head->next;if(detectLoop(head))cout<<"true";elsecout<<"false";return0;}
C
#include<stdbool.h>#include<stdio.h>#include<stdlib.h>structNode{intdata;structNode*next;};structNode*createNode(intnew_data){structNode*new_node=(structNode*)malloc(sizeof(structNode));new_node->data=new_data;new_node->next=NULL;returnnew_node;}intdetectLoop(structNode*head){// Fast and slow pointers initially points to the headstructNode*slow=head,*fast=head;// Loop that runs while fast and slow pointer are not// nullptr and not equalwhile(slow&&fast&&fast->next){slow=slow->next;fast=fast->next->next;// If fast and slow pointer points to the same node,// then the cycle is detectedif(slow==fast){returntrue;}}returnfalse;}intmain(){structNode*head=createNode(1);head->next=createNode(3);head->next->next=createNode(4);head->next->next->next=head->next;if(detectLoop(head))printf("true");elseprintf("false");return0;}
Java
classNode{intdata;Nodenext;publicNode(intx){this.data=x;this.next=null;}}classGfG{staticbooleandetectLoop(Nodehead){// Fast and slow pointers initially points to the headNodeslow=head,fast=head;// Loop that runs while fast and slow pointer are not// null and not equalwhile(slow!=null&&fast!=null&&fast.next!=null){slow=slow.next;fast=fast.next.next;// If fast and slow pointer points to the same node,// then the cycle is detectedif(slow==fast){returntrue;}}returnfalse;}publicstaticvoidmain(String[]args){Nodehead=newNode(1);head.next=newNode(3);head.next.next=newNode(4);head.next.next.next=head.next;if(detectLoop(head))System.out.println("true");elseSystem.out.println("false");}}
Python
classNode:def__init__(self,x):self.data=xself.next=NonedefdetectLoop(head):# fast and slow pointers initially points to the headslow=headfast=head# loop that runs while fast and slow pointer are not# None and not equalwhileslowandfastandfast.next:slow=slow.nextfast=fast.next.next# if fast and slow pointer points to the same node,# then the cycle is detectedifslow==fast:returnTruereturnFalseif__name__=="__main__":head=Node(1)head.next=Node(3)head.next.next=Node(4)head.next.next.next=head.nextifdetectLoop(head):print("true")else:print("false")
C#
usingSystem;classNode{publicintdata;publicNodenext;publicNode(intx){this.data=x;this.next=null;}}classGfG{staticbooldetectLoop(Nodehead){// fast and slow pointers initially points to the headNodeslow=head,fast=head;// loop that runs while fast and slow pointer are not// null and not equalwhile(slow!=null&&fast!=null&&fast.next!=null){slow=slow.next;fast=fast.next.next;// if fast and slow pointer points to the same node,// then the cycle is detectedif(slow==fast){returntrue;}}returnfalse;}staticvoidMain(){Nodehead=newNode(1);head.next=newNode(3);head.next.next=newNode(4);head.next.next.next=head.next;if(detectLoop(head))Console.WriteLine("true");elseConsole.WriteLine("false");}}
JavaScript
classNode{constructor(x){this.data=x;this.next=null;}}functiondetectLoop(head){// fast and slow pointers// initially points to the headletslow=head,fast=head;// Loop that runs while fast and slow pointer are not// null and not equalwhile(slow&&fast&&fast.next){slow=slow.next;fast=fast.next.next;// If fast and slow pointer points to the same node,// then the cycle is detectedif(slow===fast){returntrue;}}returnfalse;}// Driver Codelethead=newNode(1);head.next=newNode(3);head.next.next=newNode(4);head.next.next.next=head.next;if(detectLoop(head))console.log("true");elseconsole.log("false");
Output
true
Time Complexity: O(n) because in the worst case, both pointers traverse at most n nodes before meeting or terminating, where n is the total number of nodes in the linked list. Auxiliary Space: O(1)