BFS & DFS on Graphs and Grids — Complete Guide

Sanjeev SharmaSanjeev Sharma
6 min read

Advertisement

Why BFS/DFS on Grids?

Grid problems model many real-world scenarios: connected components (islands), shortest paths, flood fill, and multi-source spread. The key insight is that a 2-D grid is just a graph where each cell connects to its 4 (or 8) neighbours.


The 7 Core Patterns

Pattern 1 — DFS Flood Fill (mark visited in-place)

Recurse into all 4 neighbours, mutating grid to avoid revisit.

def dfs(grid, r, c):
    if r < 0 or r >= len(grid) or c < 0 or c >= len(grid[0]):
        return
    if grid[r][c] != '1':
        return
    grid[r][c] = '0'          # mark visited
    dfs(grid, r+1, c); dfs(grid, r-1, c)
    dfs(grid, r, c+1); dfs(grid, r, c-1)

Pattern 2 — BFS Shortest Path (layer-by-layer)

Use a deque; process layer by layer to get min distance.

from collections import deque
def bfs(grid, start):
    q = deque([(*start, 0)])   # (r, c, dist)
    visited = set([start])
    while q:
        r, c, d = q.popleft()
        for dr, dc in [(-1,0),(1,0),(0,-1),(0,1)]:
            nr, nc = r+dr, c+dc
            if 0 <= nr < R and 0 <= nc < C and (nr,nc) not in visited:
                visited.add((nr,nc))
                q.append((nr, nc, d+1))

Pattern 3 — Multi-Source BFS (0-1 or all-at-once)

Push all sources at once; cells get updated with min distance from any source.

q = deque()
for r in range(R):
    for c in range(C):
        if grid[r][c] == '1':
            q.append((r, c))
            dist[r][c] = 0
# standard BFS from here

Pattern 4 — Connected Components (count islands)

Iterate all cells; each unvisited land cell starts a new component.

count = 0
for r in range(R):
    for c in range(C):
        if grid[r][c] == '1':
            dfs(grid, r, c)
            count += 1

Pattern 5 — Boundary DFS (mark non-enclosed, then flip)

Start from border cells; anything reachable from border cannot be enclosed.

for r in range(R):
    for c in range(C):
        if (r in (0, R-1) or c in (0, C-1)) and grid[r][c] == 'O':
            dfs_mark(grid, r, c, 'S')   # safe
for r in range(R):
    for c in range(C):
        if grid[r][c] == 'O': grid[r][c] = 'X'
        elif grid[r][c] == 'S': grid[r][c] = 'O'

Pattern 6 — 0-1 BFS (deque with 0-weight left push)

When edges have cost 0 or 1, use deque: push cost-0 to front, cost-1 to back.

from collections import deque
dq = deque([(0, 0, 0)])   # (dist, r, c)
dist = [[inf]*C for _ in range(R)]
dist[0][0] = 0
while dq:
    d, r, c = dq.popleft()
    if d > dist[r][c]: continue
    for dr, dc in dirs:
        nr, nc = r+dr, c+dc
        cost = 0 if same_color else 1
        if dist[r][c] + cost < dist[nr][nc]:
            dist[nr][nc] = dist[r][c] + cost
            if cost == 0: dq.appendleft((dist[nr][nc], nr, nc))
            else: dq.append((dist[nr][nc], nr, nc))

Pattern 7 — BFS with State (visited = cell + state)

When the graph has extra state (e.g. keys, parity), encode it in visited set.

visited = set()
q = deque([(sr, sc, 0)])   # 0 = no key
while q:
    r, c, keys = q.popleft()
    if (r, c, keys) in visited: continue
    visited.add((r, c, keys))
    # update keys when stepping on key cell

Complexity Reference

PatternTimeSpace
DFS Flood FillO(R*C)O(R*C) stack
BFS Shortest PathO(R*C)O(R*C)
Multi-Source BFSO(R*C)O(R*C)
Connected ComponentsO(R*C)O(R*C)
Boundary DFSO(R*C)O(R*C)
0-1 BFSO(R*C)O(R*C)
BFS with StateO(RCS)O(RCS)

5-Language BFS/DFS Templates

C — DFS Grid

void dfs(char** grid, int r, int c, int R, int C) {
    if (r<0||r>=R||c<0||c>=C||grid[r][c]!='1') return;
    grid[r][c]='0';
    dfs(grid,r+1,c,R,C); dfs(grid,r-1,c,R,C);
    dfs(grid,r,c+1,R,C); dfs(grid,r,c-1,R,C);
}

C++ — BFS Grid

void bfs(vector<vector<char>>& g, int r, int c) {
    queue<pair<int,int>> q;
    q.push({r,c}); g[r][c]='0';
    int dr[]={0,0,1,-1}, dc[]={1,-1,0,0};
    while (!q.empty()) {
        auto [x,y] = q.front(); q.pop();
        for (int i=0;i<4;i++) {
            int nx=x+dr[i], ny=y+dc[i];
            if (nx>=0&&nx<g.size()&&ny>=0&&ny<g[0].size()&&g[nx][ny]=='1') {
                g[nx][ny]='0'; q.push({nx,ny});
            }
        }
    }
}

Java — BFS Grid

private void bfs(char[][] grid, int r, int c) {
    int R = grid.length, C = grid[0].length;
    Queue<int[]> q = new LinkedList<>();
    q.add(new int[]{r,c}); grid[r][c]='0';
    int[][] dirs = {{0,1},{0,-1},{1,0},{-1,0}};
    while (!q.isEmpty()) {
        int[] cur = q.poll();
        for (int[] d : dirs) {
            int nr=cur[0]+d[0], nc=cur[1]+d[1];
            if (nr>=0&&nr<R&&nc>=0&&nc<C&&grid[nr][nc]=='1') {
                grid[nr][nc]='0'; q.add(new int[]{nr,nc});
            }
        }
    }
}

JavaScript — DFS Grid

function dfs(grid, r, c) {
    if (r < 0 || r >= grid.length || c < 0 || c >= grid[0].length) return;
    if (grid[r][c] !== '1') return;
    grid[r][c] = '0';
    dfs(grid,r+1,c); dfs(grid,r-1,c);
    dfs(grid,r,c+1); dfs(grid,r,c-1);
}

Python — DFS Grid

def dfs(grid, r, c):
    if not (0 <= r < len(grid) and 0 <= c < len(grid[0])): return
    if grid[r][c] != '1': return
    grid[r][c] = '0'
    for dr, dc in [(1,0),(-1,0),(0,1),(0,-1)]:
        dfs(grid, r+dr, c+dc)

Problem Index

#ProblemPatternDifficulty
01Number of IslandsDFS Flood FillEasy
02Flood FillDFS Flood FillEasy
03Island PerimeterGrid countingEasy
04Max Area of IslandDFS + area countMedium
05Surrounded RegionsBoundary DFSMedium
06Rotting OrangesMulti-Source BFSMedium
0701 MatrixMulti-Source BFSMedium
08Walls and GatesMulti-Source BFSMedium
09Number of EnclavesBoundary DFSMedium
10Count Sub IslandsDFS subset checkMedium
11Making a Large IslandDFS + color mapHard
12Pacific Atlantic Water FlowTwo-source DFSMedium
13Shortest Path in Binary MatrixBFSMedium
14As Far from Land as PossibleMulti-Source BFSMedium
15Word SearchDFS backtrackMedium
16Number of Distinct IslandsDFS + shape hashMedium
17Number of Closed IslandsBoundary DFSMedium
18Shortest BridgeBFS + DFSMedium
19Minimum Effort PathBinary search + BFSHard
20Reachable Nodes in Subdivided GraphBFS + mathHard

Advertisement

Sanjeev Sharma

Written by

Sanjeev Sharma

Full Stack Engineer · E-mopro