GRAPHS / ALGORITHM BRIEF

Depth-first search

Depth-first search (DFS) explores a graph by going as deep as possible along one path before backtracking.

IntermediatePhase 05 / Topic 3 of 10Mental modelComplexityEdge cases
01

Overview

Depth-first search (DFS) explores a graph by going as deep as possible along one path before backtracking. It uses a stack, either the call stack through recursion or an explicit one, and a visited set so each node is processed once.

DFS is the natural tool for exploring everything reachable: counting connected components, flood-filling regions, detecting cycles, topological ordering, and generating all paths. Unlike BFS it does not find shortest paths, but it uses memory proportional to depth rather than width and is usually shorter to write.

Exploring a maze with a ball of string

You follow one corridor as far as it goes, unrolling string. At a dead end you walk back along the string to the last junction and try an untried corridor. You mark visited junctions so you never explore the same one twice.

02

When to use it

  • Explore all nodes reachable from a start: islands, provinces, regions.
  • Detect cycles in directed or undirected graphs.
  • Topological sort of a DAG (postorder).
  • Enumerate all paths or configurations (backtracking is DFS on a decision tree).
  • Tree problems, which are DFS on a special graph.
03

Problem patterns it solves

Connected components / flood fill

Recognize it when: count islands, provinces, or regions; fill an area.

  • 200. Number of Islands
  • 547. Number of Provinces
  • 695. Max Area of Island
  • 733. Flood Fill
Boundary-connected regions

Recognize it when: regions touching the border are special; start DFS from the edges.

  • 130. Surrounded Regions
  • 1020. Number of Enclaves
  • 417. Pacific Atlantic Water Flow
Cycle detection (directed, 3 colors)

Recognize it when: can all courses be finished; find safe states.

  • 207. Course Schedule
  • 802. Find Eventual Safe States
  • 1059. All Paths from Source Lead to Destination
All paths

Recognize it when: list every path from source to target in a DAG.

  • 797. All Paths From Source to Target
  • 1443. Minimum Time to Collect All Apples in a Tree
Graph cloning and copying

Recognize it when: copy structure with a visited map.

  • 133. Clone Graph
  • 138. Copy List with Random Pointer
Bridges and articulation points

Recognize it when: critical connections whose removal disconnects the graph.

  • 1192. Critical Connections in a Network
04

Where it is used in real software

Garbage collection (mark phase)

Mark-and-sweep collectors run a DFS from root references to mark every reachable object; unmarked objects are freed.

Dependency resolution and build systems

Tools like Make and Bazel run DFS to detect circular dependencies and compute build order.

Maze and puzzle solvers

Sudoku solvers, maze generators, and game AI explore choices depth-first with backtracking.

Static analysis

Compilers and linters traverse call graphs and control-flow graphs to find unreachable code.

05

Key terms

Visited set
Prevents revisiting nodes and infinite loops in cyclic graphs.
Backtracking
Returning to the previous node when all neighbors are explored.
Three colors
0 = unvisited, 1 = in the current path, 2 = finished. A 1 -> 1 edge means a directed cycle.
Discovery / finish time
When a node is first reached and when its exploration completes.
Back edge
An edge to an ancestor in the current DFS path, which indicates a cycle.
06

How it works, step by step

  1. 1
    Mark the node visited

    Do this before exploring neighbors.

  2. 2
    Process the node (preorder work)

    Count it, color it, or add it to a path.

  3. 3
    Recurse into each unvisited neighbor

    Go deep before trying the next neighbor.

  4. 4
    Finish the node (postorder work)

    Mark it done, add it to a topological order, or remove it from the current path.

  5. 5
    Repeat from every unvisited node

    This handles disconnected graphs and counts components.

DFS order from A (neighbors in alphabetical order)
Step 1 / 6
A
0
B
1
C
2
D
3
E
4
F
5

STEP 1Visit A. Neighbors of A: B, C.

07

Number of islands

grid = ["11000", "11000", "00100", "00011"]

Step 1 / 5
Scan cellValueActionIslands
(0,0)1new island: DFS sinks (0,0),(0,1),(1,0),(1,1)1
(0,1)..(1,1)0 (sunk)skip1
(2,2)1new island: DFS sinks (2,2)2
(3,3)1new island: DFS sinks (3,3),(3,4)3
(3,4)0 (sunk)skip3

NOWScan cell: (0,0) | Value: 1 | Action: new island: DFS sinks (0,0),(0,1),(1,0),(1,1) | Islands: 1

3 islands. Each DFS marks its whole island as visited, so every cell is processed a constant number of times: O(rows x cols).

08

Implementation

function numIslands(grid) {  const rows = grid.length, cols = grid[0].length;  let count = 0;  function sink(r, c) {    if (r < 0 || c < 0 || r >= rows || c >= cols || grid[r][c] !== "1") return;    grid[r][c] = "0"; // mark visited    sink(r + 1, c); sink(r - 1, c); sink(r, c + 1); sink(r, c - 1);  }  for (let r = 0; r < rows; r++) {    for (let c = 0; c < cols; c++) {      if (grid[r][c] === "1") {        count++;        sink(r, c);      }    }  }  return count;} // Iterative DFS avoids recursion limits on big graphsfunction reachable(graph, start) {  const visited = new Set([start]);  const stack = [start];  while (stack.length) {    const node = stack.pop();    for (const next of graph[node]) {      if (!visited.has(next)) {        visited.add(next);        stack.push(next);      }    }  }  return visited;} // Directed cycle detection with three colorsfunction canFinish(numCourses, prerequisites) {  const graph = Array.from({ length: numCourses }, () => []);  for (const [course, pre] of prerequisites) graph[pre].push(course);  const state = new Array(numCourses).fill(0); // 0 new, 1 visiting, 2 done  function hasCycle(u) {    if (state[u] === 1) return true;  // back edge    if (state[u] === 2) return false;    state[u] = 1;    for (const v of graph[u]) if (hasCycle(v)) return true;    state[u] = 2;    return false;  }  for (let i = 0; i < numCourses; i++) if (hasCycle(i)) return false;  return true;}
09

Complexity and performance

TimeO(V + E)

Each node and edge handled once.

SpaceO(V)

Visited set plus recursion depth.

GridO(R x C)

Recursion can reach R x C deep on a snake-shaped region.

All pathsO(2^V x V)

Exponential number of paths in the worst case.

10

Trade-offs

DFS vs BFS

DFS is simpler for reachability, components, and cycles, and uses O(depth) memory. BFS is required for shortest paths in unweighted graphs.

Recursive vs iterative

Recursion is concise but can overflow the stack on 10^5+ nodes (especially in JavaScript). Iterative DFS uses an explicit stack.

Mutating input for visited

Sinking cells saves memory but destroys the grid; use a visited array if the input must remain intact.

11

Variants and related techniques

Undirected cycle detection

A visited neighbor that is not the parent indicates a cycle.

Tarjan's algorithm

Discovery and low-link times find bridges, articulation points, and strongly connected components in O(V + E).

DFS on trees with parent

Pass the parent to avoid walking back up in undirected trees.

12

Common mistakes

  • Marking visited after the recursive call.

    Fix: Mark before exploring neighbors, or cycles cause infinite recursion.

  • Using a visited set for directed cycle detection.

    Fix: A single visited set cannot tell the current path from finished nodes; use three states.

  • Starting DFS from only one node.

    Fix: Loop over all nodes to cover disconnected components.

  • Forgetting to copy the path when saving results.

    Fix: Push a copy (new ArrayList<>(path), [...path]), not the mutable list.

13

Interview questions

How do you detect a cycle in a directed graph?

Run DFS with three states. If you reach a node that is currently on the recursion stack (state 'visiting'), you found a back edge, which means a cycle.

Why can't DFS find shortest paths in unweighted graphs?

DFS may reach a node first through a long path. BFS processes nodes in order of distance, so its first visit is always via a shortest path.

14

Practice problems

ProblemDifficultyWhat it trains
733. Flood FillEasyBasic grid DFS.
200. Number of IslandsMediumComponents.
547. Number of ProvincesMediumAdjacency matrix DFS.
130. Surrounded RegionsMediumBorder-first DFS.
207. Course ScheduleMediumThree-color cycle detection.
417. Pacific Atlantic Water FlowMediumReverse flow from borders.
1192. Critical Connections in a NetworkHardTarjan's bridges.