What is Depth-First Search?
Depth-First Search, or DFS, follows one route as far as it can before returning to try another route. The unfinished route stays on a stack, either the language call stack or one we create ourselves.
You need to know recursion, stacks, and tree or graph nodes. The short version is: finish the current branch before moving to its sibling.
The Core Idea: Follow One Path
In LC 144: Preorder Traversal, the tree begins at 1, then has left subtree 2 with children 4 and 5, and right subtree 3 with children 6 and 7. Preorder visits 1, 2, 4, 5, 3, 6, 7.
Why does 4 appear before 3? Once DFS enters the left subtree, it finishes that whole subtree before returning to the root and taking the right edge.
It is like walking through a maze while keeping a trail of breadcrumbs. You keep taking one passage until it ends, then follow the trail back to the nearest untried turn.
How Recursion Follows a Branch
The Rule You Keep True
The stack contains the exact route from the start node to the node currently being processed. When a call returns, DFS resumes at the nearest node with unfinished work.
Traversal order tells us when to process the current node:
- Preorder processes the node before its children, which is useful when state must travel downward.
- Inorder processes a binary-tree node between its children, which returns sorted values for a BST.
- Postorder waits for both children, which is useful when the parent needs their answers.
- Graph DFS marks nodes visited and follows each unvisited neighbor.
Path Sum is the one that usually trips us up. The running sum belongs to one root-to-leaf path, so each recursive call needs its own path state or must undo shared state before trying the next child.
Picking the Right Shape
From Rule to Code
- Handle the null, invalid, or already visited state first.
- Mark the current state visited when cycles are possible.
- Process the node before, between, or after recursive calls according to the needed order.
- Recurse into each valid child or neighbor.
- Return the summary the parent needs.
Every call either stops or moves to an unvisited state, so DFS finishes in O(V + E) time for a graph and uses stack space proportional to the deepest active path.
When to use it
- •You need to follow one path deeply before trying the next path.
- •A tree answer depends on work done before, between, or after visiting its children.
- •You need to explore a connected region, component, or root-to-leaf path.
- •Recursion naturally matches the shape of the input.
How to identify it
- •The input is a tree, graph, grid, or recursive state space.
- •The prompt asks whether any path works or asks you to inspect an entire connected component.
- •One active path needs to stay available while deeper work is performed.
- •Traversal order such as preorder, inorder, or postorder changes when a node is processed.
Key insights
- →DFS keeps the current path on the call stack or an explicit stack.
- →Preorder processes a node before its children, while postorder processes it after them.
- →Inorder places a binary-tree node between its left and right subtrees.
- →Graph DFS needs a visited set because an edge can lead back to an earlier node.
- →The return value should summarize exactly what the parent needs from one subtree.
Common mistakes
- 01Using the wrong traversal order for when the node result is needed.
- 02Forgetting the null or out-of-bounds base case.
- 03Skipping a visited set on a graph with cycles.
- 04Sharing mutable path state between branches without restoring it.
- 05Assuming recursion always fits the call stack on a very deep input.