Grid Algorithms
Contiguous Regions
Image Processing
Computational Geometry
Pattern Recognition

Is there an algorithm to determine contiguous colored regions in a grid?

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

In a grid, contiguous colored regions are just connected components where neighboring cells share the same value. The standard algorithms are flood fill, depth-first search, breadth-first search, or connected-component labeling, and they all solve the same core problem efficiently in linear time over the number of cells.

Model the grid as a graph

Each grid cell is a node. Two nodes are connected if:

  • they are adjacent horizontally or vertically, for 4-connectivity
  • or also diagonally, for 8-connectivity

Once you define that neighborhood rule, the problem becomes: find every connected component whose cells all have the same color.

That is why the problem shows up in image segmentation, tile games, map analysis, and flood-fill tools. The algorithmic core is the same in all of them.

A simple BFS flood-fill solution

Breadth-first search is a good default because it is iterative and easy to control:

python
1from collections import deque
2
3def find_regions(grid):
4    if not grid or not grid[0]:
5        return []
6
7    rows, cols = len(grid), len(grid[0])
8    visited = [[False] * cols for _ in range(rows)]
9    regions = []
10    directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
11
12    for r in range(rows):
13        for c in range(cols):
14            if visited[r][c]:
15                continue
16
17            color = grid[r][c]
18            queue = deque([(r, c)])
19            visited[r][c] = True
20            cells = []
21
22            while queue:
23                cr, cc = queue.popleft()
24                cells.append((cr, cc))
25
26                for dr, dc in directions:
27                    nr, nc = cr + dr, cc + dc
28                    if 0 <= nr < rows and 0 <= nc < cols:
29                        if not visited[nr][nc] and grid[nr][nc] == color:
30                            visited[nr][nc] = True
31                            queue.append((nr, nc))
32
33            regions.append({"color": color, "cells": cells})
34
35    return regions
36
37grid = [
38    ["R", "R", "G", "G"],
39    ["R", "B", "G", "G"],
40    ["B", "B", "B", "Y"],
41]
42
43for region in find_regions(grid):
44    print(region["color"], region["cells"])

This visits each cell once, so the time complexity is O(rows * cols).

DFS works too

Depth-first search solves the same problem with slightly different traversal behavior. A recursive DFS is short and readable, but large grids can hit recursion limits in some languages. An explicit stack avoids that issue.

The choice between BFS and DFS is usually about implementation preference rather than asymptotic performance. For region detection, both are standard.

Connected-component labeling for image-style workloads

If you are processing large raster images rather than game boards, the more formal term is connected-component labeling. Practical image libraries often use a two-pass algorithm or union-find structure instead of launching a fresh BFS from every unvisited pixel.

The main idea is:

  1. Scan the image row by row.
  2. Assign provisional labels to matching neighbors.
  3. Merge equivalent labels with union-find.
  4. Resolve final labels in a second pass.

This is especially useful when you want:

  • a label matrix instead of a list of cells
  • region areas, bounding boxes, or centroids
  • high throughput on large binary or multi-class images

For many application-level problems, though, a straightforward BFS or DFS is already fast enough.

Decide your connectivity rule up front

One of the most common sources of confusion is whether diagonal cells count as connected. For example, these two R cells:

text
R .
. R

belong to different regions under 4-connectivity but the same region under 8-connectivity.

That choice changes the output, so it should be defined before you implement the algorithm.

Common Pitfalls

The biggest mistake is forgetting to track visited cells. Without that, the traversal can revisit the same region indefinitely or count it multiple times.

Another issue is mixing connectivity rules. If your code checks only up, down, left, and right but your expected output assumes diagonals connect, the algorithm will appear "wrong" when the real issue is the definition.

Developers also sometimes optimize too early. For moderate grids, plain BFS or DFS is usually simpler and sufficiently fast. Save union-find or specialized image-labeling code for genuinely large workloads.

Finally, be clear about what the region should contain. Some problems want only the size, others want the cell coordinates, and others want a labeled output matrix.

Summary

  • Yes, there is a standard algorithmic solution: connected-component search using BFS, DFS, or connected-component labeling.
  • The core idea is to group adjacent cells that share the same color.
  • A BFS or DFS flood fill runs in linear time over the grid size.
  • Use 4-connectivity or 8-connectivity consistently depending on the problem definition.
  • For large image-style workloads, connected-component labeling with union-find can be more practical than repeated flood fills.

Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design