DFS Depth First Search on Graph in DSA Typescript - Time & Space Complexity
We want to understand how the time taken by Depth First Search (DFS) changes as the graph size grows.
How does DFS scale when exploring nodes and edges in a graph?
Analyze the time complexity of the following DFS code on a graph.
function dfs(node: number, graph: number[][], visited: boolean[]): void {
visited[node] = true;
for (const neighbor of graph[node]) {
if (!visited[neighbor]) {
dfs(neighbor, graph, visited);
}
}
}
This code visits each node and explores all its neighbors recursively.
Look for loops and recursive calls that repeat work.
- Primary operation: Visiting each node and checking its neighbors.
- How many times: Each node is visited once, and each edge is checked once.
As the graph grows, DFS visits all nodes and edges once.
| Input Size (n nodes, e edges) | Approx. Operations |
|---|---|
| 10 nodes, 15 edges | About 10 visits + 15 edge checks = 25 operations |
| 100 nodes, 200 edges | About 100 visits + 200 edge checks = 300 operations |
| 1000 nodes, 5000 edges | About 1000 visits + 5000 edge checks = 6000 operations |
Pattern observation: Operations grow roughly proportional to nodes plus edges.
Time Complexity: O(n + e)
This means DFS takes time proportional to the total number of nodes and edges in the graph.
[X] Wrong: "DFS always takes O(n²) time because it uses recursion and loops."
[OK] Correct: DFS visits each node and edge only once, so it does not repeat work unnecessarily. The time depends on nodes plus edges, not their square.
Understanding DFS time complexity helps you explain how graph traversal scales and why it is efficient for many problems.
"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 strategy
DFS explores nodes by going deep into one branch before backtracking to explore other branches.Step 2: Compare with other traversal methods
BFS visits neighbors first, but DFS goes deep first, matching Explore as far as possible along each branch before backtracking.Final Answer:
Explore as far as possible along each branch before backtracking -> Option AQuick Check:
DFS = deep exploration first [OK]
- Confusing DFS with BFS
- Thinking DFS visits neighbors first
- Assuming DFS visits nodes by distance
Solution
Step 1: Identify graph representation type
An adjacency list for a graph with numbered nodes is usually number[][], where each index holds neighbors.Step 2: Check parameter types
Start node is a number, so function signature with graph: number[][] and start: number is correct.Final Answer:
function dfs(graph: number[][], start: number): void -> Option CQuick Check:
Adjacency list = number[][], start node = number [OK]
- Using number[] instead of number[][] for adjacency list
- Using Map with incorrect value type
- Using string types for numeric graphs
const graph = [[1, 2], [2], [0, 3], [3]];
const visited: boolean[] = [];
const result: number[] = [];
function dfs(node: number) {
if (visited[node]) return;
visited[node] = true;
result.push(node);
for (const neighbor of graph[node]) {
dfs(neighbor);
}
}
dfs(0);
console.log(result);Solution
Step 1: Start DFS at node 0
Visit 0, mark visited, add to result: [0]. Neighbors: 1, 2.Step 2: Visit neighbor 1
Visit 1, mark visited, add: [0,1]. Neighbor: 2.Step 3: Visit neighbor 2 from 1
Visit 2, mark visited, add: [0,1,2]. Neighbors: 0 (visited), 3.Step 4: Visit neighbor 3 from 2
Visit 3, mark visited, add: [0,1,2,3]. Neighbor: 3 (already visited).Final Answer:
[0, 2, 1, 3] -> Option BQuick Check:
DFS order = [0,2,1,3] [OK]
- Not marking nodes visited before recursion
- Visiting neighbors in wrong order
- Ignoring already visited nodes
function dfs(node: number, graph: number[][], visited: boolean[]) {
visited[node] = true;
for (const neighbor of graph[node]) {
if (!visited[neighbor]) {
dfs(neighbor, graph, visited);
}
}
}
const graph = [[1], [2], [0]];
const visited = new Array(graph.length).fill(false);
dfs(0, graph, visited);
console.log(visited);Solution
Step 1: Check visited marking timing
Visited[node] is marked true before recursion, preventing revisits.Step 2: Verify recursion and base case
Recursion only happens if neighbor not visited, so no infinite loops.Final Answer:
No bug, code works correctly -> Option DQuick Check:
Visited marked before recursion = correct DFS [OK]
- Marking visited after recursion causing infinite loops
- Initializing visited array incorrectly
- Missing base case check
Solution
Step 1: Understand cycle detection in DFS
Detecting cycles requires knowing if a node is in the current recursion path (stack).Step 2: Use recursion stack tracking
Maintain a separate array to track nodes currently in recursion; if a neighbor is in this stack, a cycle exists.Step 3: Evaluate other options
Marking visited after neighbors or using BFS won't reliably detect cycles; ignoring visited nodes causes infinite loops.Final Answer:
Use a recursion stack array to track nodes in the current path and detect back edges -> Option AQuick Check:
Cycle detection = recursion stack tracking [OK]
- Not tracking recursion stack causing missed cycles
- Using BFS which doesn't track recursion path
- Marking visited too late or ignoring visited nodes
Ready to prove it?
Pass the test and this pattern moves unknown
