Cycle Detection in Undirected Graph in DSA Java - Time & Space Complexity
We want to understand how the time needed to detect a cycle in an undirected graph changes as the graph grows.
Specifically, how does the number of nodes and edges affect the work done?
Analyze the time complexity of the following code snippet.
boolean dfs(int node, int parent, List<List<Integer>> graph, boolean[] visited) {
visited[node] = true;
for (int neighbor : graph.get(node)) {
if (!visited[neighbor]) {
if (dfs(neighbor, node, graph, visited)) return true;
} else if (neighbor != parent) {
return true;
}
}
return false;
}
boolean hasCycle(int n, List<List<Integer>> graph) {
boolean[] visited = new boolean[n];
for (int i = 0; i < n; i++) {
if (!visited[i]) {
if (dfs(i, -1, graph, visited)) return true;
}
}
return false;
}
This code checks if an undirected graph has a cycle by visiting nodes using depth-first search.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The depth-first search (DFS) visits each node and explores all its neighbors.
- How many times: Each node and edge is visited once during the DFS traversal.
As the number of nodes (n) and edges (e) grow, the DFS explores all nodes and edges once.
| Input Size (n, e) | Approx. Operations |
|---|---|
| 10 nodes, 15 edges | About 10 + 15 = 25 visits |
| 100 nodes, 200 edges | About 100 + 200 = 300 visits |
| 1000 nodes, 3000 edges | About 1000 + 3000 = 4000 visits |
Pattern observation: The work grows roughly in proportion to the sum of nodes and edges.
Time Complexity: O(n + e)
This means the time to detect a cycle grows linearly with the total number of nodes and edges in the graph.
[X] Wrong: "The DFS visits every edge multiple times, so the time is much higher than O(n + e)."
[OK] Correct: Each edge is checked only twice (once from each node), so the total work is proportional to edges plus nodes, not more.
Understanding this time complexity helps you explain how graph traversal scales and why DFS is efficient for cycle detection in undirected graphs.
"What if the graph was directed instead of undirected? How would the time complexity of cycle detection change?"
Practice
Solution
Step 1: Understand DFS traversal in undirected graph
DFS visits nodes and tracks the parent node to avoid false cycle detection.Step 2: Detect cycle condition
If during DFS, a visited node is found that is not the parent, it means a back edge exists, indicating a cycle.Final Answer:
If we visit a node that is already visited and is not the parent, a cycle exists. -> Option DQuick Check:
Cycle detection in undirected graph = check visited node not parent [OK]
- Confusing parent node with visited node
- Assuming disconnected graph always has cycles
- Thinking more edges than nodes always means cycle
Solution
Step 1: Identify parameters needed for DFS cycle detection
DFS needs current node, parent node, visited array, and adjacency list graph.Step 2: Check return type and parameter types
Return type boolean indicates if cycle found; graph must be List of Lists for adjacency; parent is needed.Final Answer:
boolean dfs(int node, int parent, boolean[] visited, List<List<Integer>> graph) -> Option CQuick Check:
DFS signature with parent and boolean return = boolean dfs(int node, int parent, boolean[] visited, List graph) [OK]
- Using void return type instead of boolean
- Passing graph as List<Integer> instead of List
- Omitting parent parameter
import java.util.*;
public class GraphCycle {
static boolean dfs(int node, int parent, boolean[] visited, List graph) {
visited[node] = true;
for (int adj : graph.get(node)) {
if (!visited[adj]) {
if (dfs(adj, node, visited, graph)) return true;
} else if (adj != parent) {
return true;
}
}
return false;
}
public static void main(String[] args) {
int n = 4;
List graph = new ArrayList<>();
for (int i = 0; i < n; i++) graph.add(new ArrayList<>());
graph.get(0).add(1); graph.get(1).add(0);
graph.get(1).add(2); graph.get(2).add(1);
graph.get(2).add(3); graph.get(3).add(2);
graph.get(3).add(1); graph.get(1).add(3);
boolean[] visited = new boolean[n];
boolean hasCycle = false;
for (int i = 0; i < n; i++) {
if (!visited[i]) {
if (dfs(i, -1, visited, graph)) {
hasCycle = true;
break;
}
}
}
System.out.println(hasCycle);
}
}Solution
Step 1: Analyze graph edges and structure
Graph edges: 0-1, 1-2, 2-3, 3-1 form a cycle (1-2-3-1).Step 2: Trace DFS cycle detection logic
DFS finds visited node 1 again from 3 (not parent), so returns true indicating cycle.Final Answer:
true -> Option AQuick Check:
Cycle detected in graph = true [OK]
- Ignoring the edge 3-1 that closes the cycle
- Assuming no cycle because graph is connected
- Misunderstanding parent check in DFS
boolean dfs(int node, int parent, boolean[] visited, List graph) {
visited[node] = true;
for (int adj : graph.get(node)) {
if (!visited[adj]) {
dfs(adj, node, visited, graph);
} else if (adj != parent) {
return true;
}
}
return false;
}Solution
Step 1: Review recursive DFS calls
Recursive call dfs(adj, node, visited, graph) is made but its boolean result is ignored.Step 2: Understand impact of ignoring return value
If a cycle is detected deeper, it won't propagate true back, causing false negatives.Final Answer:
Missing return statement for recursive dfs call result -> Option BQuick Check:
Return recursive call result to detect cycles correctly [OK]
- Not returning true from recursive calls
- Confusing parent check logic
- Not marking nodes visited before recursion
0: [1, 2] 1: [0, 3] 2: [0, 3] 3: [1, 2, 4] 4: [3]Which of the following modifications will correctly detect a cycle in this graph using DFS cycle detection method?
Solution
Step 1: Understand graph structure and cycle presence
Edges form a cycle: 0-1-3-2-0. Starting DFS from 0 covers all nodes.Step 2: Apply correct DFS cycle detection method
Starting DFS from 0 with parent -1 and checking visited nodes excluding parent detects cycle correctly.Final Answer:
Start DFS from node 0 and pass -1 as parent; check visited nodes for back edges. -> Option AQuick Check:
Proper DFS start and parent check detects cycle [OK]
- Ignoring parent parameter causing false positives
- Starting DFS from leaf node only
- Marking visited nodes too late
Ready to prove it?
Pass the test and this pattern moves unknown
