DFS - Recursive + Iterative
DFS - Recursive + Iterative is a easy graphs problem solved with the bfs / dfs basics pattern.
The best approach, iterative dfs (explicit stack), runs in O(V + E) time and O(V + E) space.
Below are 2 approaches in Java, from recursive dfs up.
Problem
Depth-first search follows one path as deep as it can, then backs up to the last branch point and tries the next option. Learn it recursively first, then with an explicit stack.
Examples
Example 1
- Input
adj = {0: [1, 2], 1: [0, 3], 2: [0], 3: [1]}, start = 0- Output
recursive order [0, 1, 3, 2]
Example 2
- Input
same graph, iterative with a stack- Output
[0, 1, 3, 2] when neighbours are pushed in reverse
Constraints
- V vertices, E edges, adjacency list input.
Animated walkthrough
A narrated, step-by-step animation that builds the solution from the idea up. Press play, or step through it at your own pace.
Concepts first, then the problem and every approach, step by step.
Space to play or pause · ← → to jump a step · click or drag the bar to seek
Solutions
Try it yourself first. Then compare: each approach lists its idea, the steps, its time and space, and the Java code.
| Approach | Time | Space |
|---|---|---|
| Recursive DFS | O(V + E) | O(V) |
| Iterative DFS (explicit stack) | O(V + E) | O(V + E) |
1Recursive DFS
O(V + E)O(V)Recursion depth can reach V.Mark the node, record it, then recurse into each unvisited neighbour. Returning from the recursion is the backtracking step.
- dfs(u): seen[u] = true; record u.
- For each v in adj[u]: if not seen, dfs(v).
class Solution {
public List<Integer> dfs(int V, List<List<Integer>> adj, int start) {
List<Integer> order = new ArrayList<>();
go(start, adj, new boolean[V], order);
return order;
}
private void go(int u, List<List<Integer>> adj, boolean[] seen, List<Integer> order) {
seen[u] = true;
order.add(u);
for (int v : adj.get(u)) if (!seen[v]) go(v, adj, seen, order);
}
}2Iterative DFS (explicit stack)
O(V + E)O(V + E)The stack can hold duplicate entries, up to E.Push the start node. Pop a node; if already visited, skip it; otherwise visit it and push its neighbours. Push them in reverse to match the recursive order. Mark on pop, because a node can be pushed several times before it is visited.
- stack = [start].
- Pop u; if seen, continue; seen[u] = true; record u.
- Push neighbours in reverse order.
class Solution {
public List<Integer> dfs(int V, List<List<Integer>> adj, int start) {
List<Integer> order = new ArrayList<>();
boolean[] seen = new boolean[V];
Deque<Integer> st = new ArrayDeque<>();
st.push(start);
while (!st.isEmpty()) {
int u = st.pop();
if (seen[u]) continue;
seen[u] = true;
order.add(u);
List<Integer> nb = adj.get(u);
for (int i = nb.size() - 1; i >= 0; i--) if (!seen[nb.get(i)]) st.push(nb.get(i));
}
return order;
}
}Edge cases to test
- Very deep graphs (recursion depth up to V; iterative avoids stack overflow)
- Disconnected graph
Hints
Hint 1
DFS goes as deep as possible before backing up. The call stack is the stack; the iterative version makes it explicit.
FAQ
What is the best time complexity for DFS - Recursive + Iterative?
Iterative DFS (explicit stack) runs in O(V + E) time and O(V + E) extra space.
Which pattern does DFS - Recursive + Iterative use?
It is a graphs problem that uses the bfs / dfs basics pattern. Other problems with the same pattern: BFS - Normal + Level by Level.
Is there a brute force solution for DFS - Recursive + Iterative?
Yes. Recursive DFS takes O(V + E) time and O(V) space. Mark the node, record it, then recurse into each unvisited neighbour.
Which edge cases should I test for DFS - Recursive + Iterative?
Very deep graphs (recursion depth up to V; iterative avoids stack overflow); Disconnected graph.