Given a directed graph represented by its adjacency list adj[][], determine whether the graph contains a cycle/Loop or not. A cycle is a path that starts and ends at the same vertex, following the direction of edges.
Examples:
Input: adj[][] = [[1], [2], [0, 3], []]
Output: true Explanation: There is a cycle 0 -> 1 -> 2 -> 0.
Input: adj[][] = [[2], [0], []]
Output: false Explanation: There is no cycle in the graph.
[Approach 1] Using DFS - O(V + E) Time and O(V) Space
To detect a cycle in a directed graph, we use Depth First Search (DFS). In DFS, we go as deep as possible from a starting node. If during this process, we reach a node that we’ve already visited in the same DFS path, it means we’ve gone back to an ancestor — this shows a cycle exists. But there’s a problem: When we start DFS from one node, some nodes get marked as visited. Later, when we start DFS from another node, those visited nodes may appear again, even if there’s no cycle. So, using only visited[] isn’t enough.
To fix this, we use two arrays:
visited[] - marks nodes visited at least once.
recStack[] - marks nodes currently in the recursion (active) path.
If during DFS we reach a node that’s already in the recStack, we’ve found a path from the current node back to one of its ancestors, forming a cycle. As soon as we finish exploring all paths from a node, we remove it from the recursion stack by marking recStack[node] = false. This ensures that only the nodes in the current DFS path are tracked.
Illustration:
C++
//Driver Code Starts#include<iostream>#include<vector>usingnamespacestd;//Driver Code Ends// Utility DFS function to detect cycle in a directed graphboolisCyclicUtil(vector<vector<int>>&adj,intu,vector<bool>&visited,vector<bool>&recStack){// node is already in recursion stack cycle foundif(recStack[u])returntrue;// already processed no need to visit againif(visited[u])returnfalse;visited[u]=true;recStack[u]=true;// Recur for all adjacent nodesfor(intv:adj[u]){if(isCyclicUtil(adj,v,visited,recStack))returntrue;}// remove from recursion stack before backtrackingrecStack[u]=false;returnfalse;}// Function to detect cycle in a directed graphboolisCyclic(vector<vector<int>>&adj){intV=adj.size();vector<bool>visited(V,false);vector<bool>recStack(V,false);// Run DFS from every unvisited nodefor(inti=0;i<V;i++){if(!visited[i]&&isCyclicUtil(adj,i,visited,recStack))returntrue;}returnfalse;}//Driver Code Startsintmain(){vector<vector<int>>adj={{1},{2},{0,3}};cout<<(isCyclic(adj)?"true":"false")<<endl;return0;}//Driver Code Ends
Java
//Driver Code Startsimportjava.util.ArrayList;publicclassGFG{//Driver Code Ends// Utility DFS function to detect cycle in a directed graphstaticbooleanisCyclicUtil(ArrayList<ArrayList<Integer>>adj,intu,boolean[]visited,boolean[]recStack){// Node already in recursion stack cycle foundif(recStack[u])returntrue;// Already processed no need to visit againif(visited[u])returnfalse;visited[u]=true;recStack[u]=true;// Recur for all adjacent nodesfor(intv:adj.get(u)){if(isCyclicUtil(adj,v,visited,recStack))returntrue;}// Remove from recursion stack before backtrackingrecStack[u]=false;returnfalse;}// Function to detect cycle in a directed graphstaticbooleanisCyclic(ArrayList<ArrayList<Integer>>adj){intV=adj.size();boolean[]visited=newboolean[V];boolean[]recStack=newboolean[V];// Run DFS from every unvisited nodefor(inti=0;i<V;i++){if(!visited[i]&&isCyclicUtil(adj,i,visited,recStack))returntrue;}returnfalse;}//Driver Code Starts// Function to add an edge to the adjacency liststaticvoidaddEdge(ArrayList<ArrayList<Integer>>adj,intu,intv){adj.get(u).add(v);}publicstaticvoidmain(String[]args){intV=4;ArrayList<ArrayList<Integer>>adj=newArrayList<>();for(inti=0;i<V;i++){adj.add(newArrayList<>());}// Add directed edgesaddEdge(adj,0,1);addEdge(adj,1,2);addEdge(adj,2,0);addEdge(adj,2,3);System.out.println(isCyclic(adj)?"true":"false");}}//Driver Code Ends
Python
# Utility DFS function to detect cycle in a directed graphdefisCyclicUtil(adj,u,visited,recStack):# node is already in recursion stack cycle foundifrecStack[u]:returnTrue# already processed no need to visit againifvisited[u]:returnFalsevisited[u]=TruerecStack[u]=True# Recur for all adjacent nodesforvinadj[u]:ifisCyclicUtil(adj,v,visited,recStack):returnTrue# remove from recursion stack before backtrackingrecStack[u]=FalsereturnFalse# Function to detect cycle in a directed graphdefisCyclic(adj):V=len(adj)visited=[False]*VrecStack=[False]*V# Run DFS from every unvisited nodeforiinrange(V):ifnotvisited[i]andisCyclicUtil(adj,i,visited,recStack):returnTruereturnFalse#Driver Code Startsif__name__=="__main__":adj=[[1],[2],[0,3]]print("true"ifisCyclic(adj)else"false")#Driver Code Ends
C#
//Driver Code StartsusingSystem;usingSystem.Collections.Generic;classGFG{// Utility DFS function to detect cycle in a directed graph//Driver Code EndsstaticboolisCyclicUtil(List<List<int>>adj,intu,bool[]visited,bool[]recStack){// Node already in recursion stack cycle foundif(recStack[u])returntrue;// Already processed → no need to visit againif(visited[u])returnfalse;visited[u]=true;recStack[u]=true;// Recur for all adjacent nodesforeach(intvinadj[u]){if(isCyclicUtil(adj,v,visited,recStack))returntrue;}// Remove from recursion stack before backtrackingrecStack[u]=false;returnfalse;}// Function to detect cycle in a directed graphstaticboolisCyclic(List<List<int>>adj){intV=adj.Count;bool[]visited=newbool[V];bool[]recStack=newbool[V];// Run DFS from every unvisited nodefor(inti=0;i<V;i++){if(!visited[i]&&isCyclicUtil(adj,i,visited,recStack))returntrue;}returnfalse;}//Driver Code Starts// Function to add an edge to the adjacency liststaticvoidaddEdge(List<List<int>>adj,intu,intv){adj[u].Add(v);}staticvoidMain(){intV=4;List<List<int>>adj=newList<List<int>>();for(inti=0;i<V;i++){adj.Add(newList<int>());}// Add directed edgesaddEdge(adj,0,1);addEdge(adj,1,2);addEdge(adj,2,0);addEdge(adj,2,3);Console.WriteLine(isCyclic(adj)?"true":"false");}}//Driver Code Ends
JavaScript
// Utility DFS function to detect cycle in a directed graphfunctionisCyclicUtil(adj,u,visited,recStack){// node is already in recursion stack cycle foundif(recStack[u])returntrue;// already processed no need to visit againif(visited[u])returnfalse;visited[u]=true;recStack[u]=true;// Recur for all adjacent nodesfor(letvofadj[u]){if(isCyclicUtil(adj,v,visited,recStack))returntrue;}// remove from recursion stack before backtrackingrecStack[u]=false;returnfalse;}// Function to detect cycle in a directed graphfunctionisCyclic(adj){constV=adj.length;constvisited=Array(V).fill(false);constrecStack=Array(V).fill(false);// Run DFS from every unvisited nodefor(leti=0;i<V;i++){if(!visited[i]&&isCyclicUtil(adj,i,visited,recStack))returntrue;}returnfalse;}// Driver Code//Driver Code StartsletV=4;constadj=[[1],[2],[0,3]];console.log(isCyclic(adj)?"true":"false");//Driver Code Ends
Output
true
[Approach 2] Using Topological Sorting - O(V + E) Time and O(V) Space
The idea is to use Kahn’s algorithm because it works only for Directed Acyclic Graphs (DAGs). So, while performing topological sorting using Kahn’s algorithm, if we are able to include all the vertices in the topological order, it means the graph has no cycle and is a DAG. However, if at the end there are still some vertices left (i.e., their in-degree never becomes 0), it means those vertices are part of a cycle. Hence, if we cannot get all the vertices in the topological sort, the graph must contain at least one cycle.
C++
//Driver Code Starts#include<iostream>#include<vector>#include<queue>usingnamespacestd;//Driver Code EndsboolisCyclic(vector<vector<int>>&adj){intV=adj.size();// Array to store in-degree of each vertexvector<int>inDegree(V,0);queue<int>q;// Count of visited (processed) nodesintvisited=0;//Compute in-degrees of all verticesfor(intu=0;u<V;++u){for(intv:adj[u]){inDegree[v]++;}}// Add all vertices with in-degree 0 to the queuefor(intu=0;u<V;++u){if(inDegree[u]==0){q.push(u);}}// Perform BFS (Topological Sort)while(!q.empty()){intu=q.front();q.pop();visited++;// Reduce in-degree of neighborsfor(intv:adj[u]){inDegree[v]--;if(inDegree[v]==0){// Add to queue when in-degree becomes 0q.push(v);}}}// If visited nodes != total nodes, a cycle existsreturnvisited!=V;}//Driver Code Startsintmain(){vector<vector<int>>adj={{1},{2},{0,3}};cout<<(isCyclic(adj)?"true":"false")<<endl;return0;}//Driver Code Ends
Java
//Driver Code Startsimportjava.util.Queue;importjava.util.LinkedList;importjava.util.ArrayList;publicclassGFG{//Driver Code EndsstaticbooleanisCyclic(ArrayList<ArrayList<Integer>>adj){intV=adj.size();// Array to store in-degree of each vertexint[]inDegree=newint[V];Queue<Integer>q=newLinkedList<>();// Count of visited (processed) nodesintvisited=0;// Compute in-degrees of all verticesfor(intu=0;u<V;++u){for(intv:adj.get(u)){inDegree[v]++;}}// Add all vertices with in-degree 0 to the queuefor(intu=0;u<V;++u){if(inDegree[u]==0){q.add(u);}}// Perform BFS (Topological Sort)while(!q.isEmpty()){intu=q.poll();visited++;// Reduce in-degree of neighborsfor(intv:adj.get(u)){inDegree[v]--;if(inDegree[v]==0){// Add to queue when in-degree becomes 0q.add(v);}}}// If visited nodes != total nodes, a cycle existsreturnvisited!=V;}//Driver Code Starts// Function to add an edge to the adjacency liststaticvoidaddEdge(ArrayList<ArrayList<Integer>>adj,intu,intv){adj.get(u).add(v);}publicstaticvoidmain(String[]args){intV=4;ArrayList<ArrayList<Integer>>adj=newArrayList<>();for(inti=0;i<V;i++){adj.add(newArrayList<>());}// Add edgesaddEdge(adj,0,1);addEdge(adj,1,2);addEdge(adj,2,0);addEdge(adj,2,3);System.out.println(isCyclic(adj)?"true":"false");}}//Driver Code Ends
Python
#Driver Code Startsfromcollectionsimportdeque#Driver Code EndsdefisCyclic(adj):V=max(max(sub)ifsubelse0forsubinadj)+1# Array to store in-degree of each vertexinDegree=[0]*Vq=deque()# Count of visited (processed) nodesvisited=0# Compute in-degrees of all verticesforuinrange(V):forvinadj[u]:inDegree[v]+=1# Add all vertices with in-degree 0 to the queueforuinrange(V):ifinDegree[u]==0:q.append(u)# Perform BFS (Topological Sort)whileq:u=q.popleft()visited+=1# Reduce in-degree of neighborsforvinadj[u]:inDegree[v]-=1ifinDegree[v]==0:# Add to queue when in-degree becomes 0q.append(v)# If visited nodes != total nodes, a cycle existsreturnvisited!=V#Driver Code Startsif__name__=="__main__":adj=[[1],[2],[0,3],[]]print("true"ifisCyclic(adj)else"false")#Driver Code Ends
C#
//Driver Code StartsusingSystem;usingSystem.Collections.Generic;classGFG{//Driver Code EndsstaticboolisCyclic(List<List<int>>adj){intV=adj.Count;// Array to store in-degree of each vertexint[]inDegree=newint[V];Queue<int>q=newQueue<int>();// Count of visited (processed) nodesintvisited=0;// Compute in-degrees of all verticesfor(intu=0;u<V;++u){foreach(intvinadj[u]){inDegree[v]++;}}// Add all vertices with in-degree 0 to the queuefor(intu=0;u<V;++u){if(inDegree[u]==0){q.Enqueue(u);}}// Perform BFS (Topological Sort)while(q.Count>0){intu=q.Dequeue();visited++;// Reduce in-degree of neighborsforeach(intvinadj[u]){inDegree[v]--;if(inDegree[v]==0){// Add to queue when in-degree becomes 0q.Enqueue(v);}}}// If visited nodes != total nodes, a cycle existsreturnvisited!=V;}//Driver Code Starts// Function to add an edge to the adjacency liststaticvoidaddEdge(List<List<int>>adj,intu,intv){adj[u].Add(v);}staticvoidMain(){intV=4;List<List<int>>adj=newList<List<int>>();for(inti=0;i<V;i++){adj.Add(newList<int>());}// Add edgesaddEdge(adj,0,1);addEdge(adj,1,2);addEdge(adj,2,0);addEdge(adj,2,3);Console.WriteLine(isCyclic(adj)?"true":"false");}}//Driver Code Ends
JavaScript
//Driver Code StartsconstDenque=require("denque");//Driver Code EndsfunctionisCyclic(adj){constV=adj.length;// Array to store in-degree of each vertexconstinDegree=newArray(V).fill(0);constq=newDenque();// Count of visited (processed) nodesletvisited=0;//Compute in-degrees of all verticesfor(letu=0;u<V;++u){for(letvofadj[u]){inDegree[v]++;}}// Add all vertices with in-degree 0 to the queuefor(letu=0;u<V;++u){if(inDegree[u]===0){q.push(u);}}// Perform BFS (Topological Sort)while(!q.isEmpty()){constu=q.shift();visited++;// Reduce in-degree of neighborsfor(letvofadj[u]){inDegree[v]--;if(inDegree[v]===0){// Add to queue when in-degree becomes 0q.push(v);}}}// If visited nodes != total nodes, a cycle existsreturnvisited!==V;}//Driver Code Starts// Driver Codeconstadj=[[1],[2],[0,3],[]];console.log(isCyclic(adj)?"true":"false");//Driver Code Ends