DFS Depth First Search on Graph in DSA Javascript - Time & Space Complexity
We want to understand how the time taken by Depth First Search (DFS) grows as the graph size increases.
Specifically, how does DFS's work change when the graph has more nodes and edges?
Analyze the time complexity of the following DFS code on a graph.
function dfs(graph, start, visited = new Set()) {
visited.add(start);
for (const neighbor of graph[start]) {
if (!visited.has(neighbor)) {
dfs(graph, neighbor, visited);
}
}
}
This code visits all nodes reachable from the start node using DFS traversal.
Look at what repeats in this DFS code.
- Primary operation: Visiting each node and checking its neighbors.
- How many times: Each node is visited once, and each edge is checked once during traversal.
As the graph grows, DFS visits every node and edge once.
| Input Size (n nodes, e edges) | Approx. Operations |
|---|---|
| 10 nodes, 15 edges | ~25 operations (10 nodes + 15 edges) |
| 100 nodes, 200 edges | ~300 operations (100 + 200) |
| 1000 nodes, 5000 edges | ~6000 operations (1000 + 5000) |
Pattern observation: The work grows roughly with the sum of nodes and edges, so more nodes or edges means more work.
Time Complexity: O(n + e)
This means DFS takes time proportional to the total number of nodes plus edges in the graph.
[X] Wrong: "DFS always takes O(n²) time because it visits nodes multiple times."
[OK] Correct: DFS marks nodes as visited, so each node and edge is processed only once, avoiding repeated work.
Understanding DFS time complexity helps you explain how graph traversals scale and why DFS is efficient for exploring connected parts of graphs.
"What if the graph is represented as an adjacency matrix instead of adjacency lists? How would the time complexity change?"
Practice
Solution
Step 1: Understand DFS traversal
DFS explores a path deeply before moving to another path.Step 2: Compare with other traversals
BFS visits nodes level by level, but DFS goes deep first.Final Answer:
It explores as far as possible along each branch before backtracking. -> Option CQuick Check:
DFS = deep exploration first [OK]
- Confusing DFS with BFS
- Thinking DFS visits nodes randomly
- Assuming DFS only visits direct neighbors
graph?Solution
Step 1: Identify suitable data structure for visited nodes
A Set is ideal to track visited nodes efficiently.Step 2: Check function signature correctness
Usingvisited = new Set()initializes visited nodes properly.Final Answer:
function dfs(node, visited = new Set()) { -> Option AQuick Check:
Use Set for visited nodes [OK]
- Using array or object incorrectly for visited
- Initializing visited as a number
- Not initializing visited parameter
const graph = {
1: [2, 3],
2: [4],
3: [],
4: []
};
function dfs(node, visited = new Set()) {
visited.add(node);
for (const neighbor of graph[node]) {
if (!visited.has(neighbor)) {
dfs(neighbor, visited);
}
}
return Array.from(visited);
}
console.log(dfs(1));What is the output?
Solution
Step 1: Start DFS from node 1
Visit 1, then neighbors 2 and 3 in order.Step 2: Visit neighbors recursively
From 2, visit 4. From 3, no neighbors. Order: 1, 2, 4, 3.Final Answer:
[1, 2, 4, 3] -> Option DQuick Check:
DFS order = 1,2,4,3 [OK]
- Visiting neighbors in wrong order
- Confusing BFS order with DFS
- Not converting Set to array properly
const graph = {
1: [2, 3],
2: [4],
3: [],
4: []
};
function dfs(node, visited = new Set()) {
visited.add(node);
for (const neighbor of graph[node]) {
if (visited.has(neighbor)) {
dfs(neighbor, visited);
}
}
return visited;
}
console.log(Array.from(dfs(1)));
Solution
Step 1: Check the neighbor visit condition
It incorrectly calls dfs if neighbor is already visited, causing infinite recursion.Step 2: Correct the condition
Change to if (!visited.has(neighbor)) to visit unvisited neighbors only.Final Answer:
The condition should be if (!visited.has(neighbor)) instead of if (visited.has(neighbor)) -> Option AQuick Check:
Visit only unvisited neighbors [OK]
- Calling DFS on already visited nodes
- Using wrong data structure for visited
- Returning wrong type from DFS
const graph = {
1: [2, 3],
2: [4],
3: [5],
4: [],
5: []
};
function dfs(node, target, visited = new Set()) {
if (node === target) return true;
visited.add(node);
for (const neighbor of graph[node]) {
if (!visited.has(neighbor)) {
if (dfs(neighbor, target, visited)) return true;
}
}
return false;
}
console.log(dfs(1, 5));What will be the output and why?
Solution
Step 1: Check DFS path search logic
DFS returns true immediately when target node is found.Step 2: Trace path from 1 to 5
Path exists: 1 -> 3 -> 5, so DFS returns true.Final Answer:
true, because DFS finds a path 1 -> 3 -> 5 -> Option BQuick Check:
DFS finds path = true [OK]
- Assuming direct connection needed
- Ignoring early return on target found
- Not updating visited set properly
Ready to prove it?
Pass the test and this pattern moves unknown
