Skip to main content

๐Ÿ•ณ๏ธ DFS (Depth-First Search)

Conceptโ€‹

DFS explores as far as possible along each branch before backtracking. It uses a stack (either the call stack via recursion, or an explicit stack).

DFS is the backbone of backtracking, cycle detection, connected component finding, and topological sort.


When to Useโ€‹

  • Explore all paths or all possibilities (exhaustive search)
  • Connected components in a graph or grid
  • Cycle detection in directed/undirected graphs
  • Topological sort (process nodes after dependencies)
  • Tree traversals (preorder, inorder, postorder)
  • Problems asking "does a path exist" or "count paths"

DFS vs BFSโ€‹

DFSBFS
Data structureStack (call stack / explicit)Queue
Shortest pathโŒ (not guaranteed)โœ… (unweighted graphs)
Memory for deep treesโŒ (stack overflow risk)โœ…
Memory for wide graphsโœ…โŒ
Find any pathโœ… fastslower
Explore ALL pathsโœ… naturalcomplex

Java Templateโ€‹

Recursive DFS on Gridโ€‹

int[][] dirs = {{0,1},{0,-1},{1,0},{-1,0}};

void dfs(int[][] grid, boolean[][] visited, int r, int c) {
// Base cases
if (r < 0 || r >= grid.length || c < 0 || c >= grid[0].length) return;
if (visited[r][c] || grid[r][c] == 0) return;

visited[r][c] = true; // mark before recursing

for (int[] dir : dirs) {
dfs(grid, visited, r + dir[0], c + dir[1]);
}
}

DFS with Backtracking on Graphโ€‹

void dfs(int node, Set<Integer> visited, Map<Integer, List<Integer>> graph) {
visited.add(node);

for (int neighbor : graph.getOrDefault(node, List.of())) {
if (!visited.contains(neighbor)) {
dfs(neighbor, visited, graph);
}
}
}

Worked Example 1: Number of Islandsโ€‹

public int numIslands(char[][] grid) {
int count = 0;
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[0].length; j++) {
if (grid[i][j] == '1') {
dfs(grid, i, j);
count++;
}
}
}
return count;
}

private void dfs(char[][] grid, int r, int c) {
if (r < 0 || r >= grid.length || c < 0 || c >= grid[0].length
|| grid[r][c] != '1') return;

grid[r][c] = '0'; // mark as visited by "sinking" the island

dfs(grid, r+1, c);
dfs(grid, r-1, c);
dfs(grid, r, c+1);
dfs(grid, r, c-1);
}

Worked Example 2: Detect Cycle in Directed Graph (Topological Sort via DFS)โ€‹

// WHITE=0 (unvisited), GRAY=1 (in current path), BLACK=2 (fully processed)
public boolean hasCycle(int n, int[][] edges) {
Map<Integer, List<Integer>> graph = new HashMap<>();
for (int[] e : edges) graph.computeIfAbsent(e[0], k -> new ArrayList<>()).add(e[1]);

int[] color = new int[n];
for (int i = 0; i < n; i++) {
if (color[i] == 0 && dfs(graph, color, i)) return true;
}
return false;
}

boolean dfs(Map<Integer, List<Integer>> graph, int[] color, int node) {
color[node] = 1; // GRAY โ€” in current path

for (int neighbor : graph.getOrDefault(node, List.of())) {
if (color[neighbor] == 1) return true; // back edge โ†’ cycle
if (color[neighbor] == 0 && dfs(graph, color, neighbor)) return true;
}

color[node] = 2; // BLACK โ€” fully done
return false;
}

Worked Example 3: Pacific Atlantic Water Flowโ€‹

public List<List<Integer>> pacificAtlantic(int[][] heights) {
int m = heights.length, n = heights[0].length;
boolean[][] pacific = new boolean[m][n];
boolean[][] atlantic = new boolean[m][n];

// DFS from all edges inward (water flows from low to high in reverse)
for (int i = 0; i < m; i++) {
dfs(heights, pacific, i, 0);
dfs(heights, atlantic, i, n - 1);
}
for (int j = 0; j < n; j++) {
dfs(heights, pacific, 0, j);
dfs(heights, atlantic, m - 1, j);
}

List<List<Integer>> result = new ArrayList<>();
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
if (pacific[i][j] && atlantic[i][j])
result.add(Arrays.asList(i, j));
return result;
}

int[][] dirs = {{0,1},{0,-1},{1,0},{-1,0}};

void dfs(int[][] h, boolean[][] visited, int r, int c) {
visited[r][c] = true;
for (int[] d : dirs) {
int nr = r + d[0], nc = c + d[1];
if (nr >= 0 && nr < h.length && nc >= 0 && nc < h[0].length
&& !visited[nr][nc] && h[nr][nc] >= h[r][c]) {
dfs(h, visited, nr, nc);
}
}
}

LeetCode Problemsโ€‹

๐ŸŸข Easyโ€‹

#ProblemKey Idea
104Maximum Depth of Binary TreeTree DFS
112Path SumTree DFS
733Flood FillGrid DFS

๐ŸŸก Mediumโ€‹

#ProblemKey Idea
200Number of IslandsGrid DFS
207Course ScheduleCycle detection
210Course Schedule IITopo sort
417Pacific Atlantic Water FlowReverse DFS
547Number of ProvincesConnected components
695Max Area of IslandGrid DFS + area
1020Number of EnclavesBorder DFS

๐Ÿ”ด Hardโ€‹

#ProblemKey Idea
329Longest Increasing Path in MatrixDFS + memoization
827Making A Large IslandIsland labeling + merge