Cycle Detection in Undirected Graph in DSA Javascript - Time & Space Complexity
We want to know how the time needed to find a cycle in an undirected graph changes as the graph grows.
How does the number of nodes and edges affect the work done?
Analyze the time complexity of the following code snippet.
function hasCycle(graph) {
const visited = new Set();
function dfs(node, parent) {
visited.add(node);
for (const neighbor of graph[node]) {
if (!visited.has(neighbor)) {
if (dfs(neighbor, node)) return true;
} else if (neighbor !== parent) {
return true;
}
}
return false;
}
for (const node in graph) {
if (!visited.has(node)) {
if (dfs(node, null)) 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 its neighbors.
- How many times: Each node and edge is visited once during the DFS traversal.
As the graph grows with more nodes and edges, the DFS explores more connections.
| Input Size (n nodes, m edges) | Approx. Operations |
|---|---|
| 10 nodes, 15 edges | About 40 visits (nodes + edges) |
| 100 nodes, 200 edges | About 500 visits |
| 1000 nodes, 3000 edges | About 4000 visits |
Pattern observation: The work grows roughly with the sum of nodes and edges, increasing linearly.
Time Complexity: O(n + m)
This means the time grows linearly with the number of nodes plus edges in the graph.
[X] Wrong: "The DFS visits every edge multiple times, so time is much higher than linear."
[OK] Correct: Each edge is checked only twice (once from each node), so total work stays proportional to edges plus nodes.
Understanding this time complexity helps you explain how graph traversal scales, a key skill for many coding challenges.
"What if the graph was directed instead of undirected? How would the time complexity 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 cycle exists.Final Answer:
If we visit a node that is already visited and is not the parent, a cycle exists. -> Option BQuick Check:
Cycle detection in undirected graph = check visited node not parent [OK]
- Ignoring the parent node in cycle check
- Assuming more edges than nodes always means cycle
- Confusing cycle detection logic with directed graphs
Solution
Step 1: Understand adjacency list format
An adjacency list maps each node to an array of its neighbors.Step 2: Check each option
const graph = {0: [1, 2], 1: [0, 3], 2: [0], 3: [1]}; correctly maps nodes to arrays of neighbors. const graph = [[0,1], [1,2], [2,3]]; is edge list, not adjacency list. const graph = {0: 1, 1: 2, 2: 3}; maps nodes to single values, not arrays. const graph = [[1, 2], [0], [0], [1]]; is an array of arrays but connections are not symmetric (node 1 missing neighbor 3).Final Answer:
const graph = {0: [1, 2], 1: [0, 3], 2: [0], 3: [1]}; -> Option AQuick Check:
Adjacency list = node keys with neighbor arrays [OK]
- Using edge list instead of adjacency list
- Mapping nodes to single values, not arrays
- Using arrays without keys for adjacency list
const graph = {0: [1, 2], 1: [0, 3], 2: [0], 3: [1]};
function dfs(node, parent, visited) {
visited[node] = true;
for (const neighbor of graph[node]) {
if (!visited[neighbor]) {
if (dfs(neighbor, node, visited)) return true;
} else if (neighbor !== parent) {
return true;
}
}
return false;
}
const visited = {};
const hasCycle = dfs(0, -1, visited);
console.log(hasCycle);Solution
Step 1: Trace DFS calls and visited nodes
Start at node 0, mark visited. Visit neighbors 1 and 2. Both lead to nodes without cycles.Step 2: Check for cycle condition
No neighbor is visited again except parent, so no cycle detected. DFS returns false.Final Answer:
false -> Option CQuick Check:
No back edge found = false [OK]
- Confusing parent node with cycle neighbor
- Assuming any visited node means cycle
- Not initializing visited properly
function dfs(node, parent, visited) {
visited[node] = true;
for (const neighbor of graph[node]) {
if (!visited[neighbor]) {
if (dfs(neighbor, node, visited)) return true;
} else if (neighbor === parent) {
return true;
}
}
return false;
}Solution
Step 1: Analyze cycle detection condition
The code returns true if neighbor equals parent, which is incorrect because parent is allowed to be visited.Step 2: Correct condition for cycle detection
It should return true if neighbor is visited and neighbor is NOT the parent, indicating a cycle.Final Answer:
The condition 'neighbor === parent' should be 'neighbor !== parent' to detect cycles. -> Option DQuick Check:
Cycle if visited neighbor not parent [OK]
- Returning true when neighbor is parent
- Not initializing visited before DFS
- Returning false too early inside loop
const graph = {
0: [1, 2],
1: [0, 2, 3],
2: [0, 1, 4],
3: [1],
4: [2]
};
Select the correct set of edges that create a cycle.Solution
Step 1: Identify cycles by checking connected edges
Edges (0-1), (1-2), and (2-0) connect nodes in a triangle, forming a cycle.Step 2: Verify other edges
Edges involving nodes 3 and 4 do not form cycles as they are connected linearly.Final Answer:
Edges (0-1), (1-2), (2-0) -> Option AQuick Check:
Triangle edges form cycle [OK]
- Assuming linear chains form cycles
- Ignoring the triangle formed by nodes 0,1,2
- Confusing edge directions in undirected graph
Ready to prove it?
Pass the test and this pattern moves unknown
