Skip to content
Reliable Data Engineering
Practice problem medium bfsdfsgraphsmatrix
Practise with timer, notes and rubric

Count Connected Regions in a Grid (Islands)

Pattern: Graphs: BFS, DFS and Union-Find · Difficulty: Medium · Asked at: Amazon, Google, Meta, Microsoft

Classic version: LeetCode 200 · LeetCode 695

Problem

grid is a list of strings of '1' (land) and '0' (water). Return (count, largest): the number of islands (groups of land connected horizontally or vertically) and the size of the largest island in cells. Don’t modify the input.

Examples

islands(["11000",
         "11000",
         "00100",
         "00011"]) → (3, 4)

Starter code

def islands(grid: list[str]) -> tuple[int, int]:
    pass

Hints

Hint 1

Scan every cell. When you find unvisited land, it starts a new island: explore everything reachable from it and mark it visited.

Hint 2

Use an explicit queue (BFS) or stack. Recursive DFS can hit Python’s recursion limit on a 1000×1000 grid.

Where this shows up in data engineering

Connected components are how you cluster linked records: sessions sharing a device, accounts sharing an email, tables connected by lineage. On a grid it’s region detection on heatmaps or geo tiles. At scale the same problem is solved with union-find or iterative label propagation (GraphFrames’ connectedComponents).

Solution

from collections import deque


def islands(grid):
    if not grid:
        return (0, 0)
    rows, cols = len(grid), len(grid[0])
    seen = set()
    count = largest = 0
    for r in range(rows):
        for c in range(cols):
            if grid[r][c] != "1" or (r, c) in seen:
                continue
            count += 1
            size, q = 0, deque([(r, c)])
            seen.add((r, c))
            while q:
                x, y = q.popleft()
                size += 1
                for nx, ny in ((x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)):
                    if 0 <= nx < rows and 0 <= ny < cols and grid[nx][ny] == "1" and (nx, ny) not in seen:
                        seen.add((nx, ny))          # mark on enqueue, not dequeue
                        q.append((nx, ny))
            largest = max(largest, size)
    return (count, largest)

Tests

Your solution should pass these:

assert islands(["11000", "11000", "00100", "00011"]) == (3, 4)
assert islands(["11110", "11010", "11000", "00000"]) == (1, 9)
assert islands(["000"]) == (0, 0)
assert islands([]) == (0, 0)
assert islands(["101", "010", "101"]) == (5, 1)
big = ["1" * 300] * 300
assert islands(big) == (1, 90000)

Explanation

Algorithm: each land cell is visited once; BFS from every unvisited land cell labels one component. O(R·C) time and space.

Mark on enqueue: adding to seen when pushing (not when popping) prevents the same cell being queued many times by different neighbours.

Why iterative: a 300×300 all-land grid would recurse 90,000 deep. Python’s default limit is 1,000. Interviewers notice this.

Alternatives: union-find over land cells (great when land arrives incrementally, as in “number of islands II”); in-place marking (grid[r][c] = '0') saves memory but mutates input, so ask first.

Follow-up questions

Land cells are added one at a time; report the island count after each addition.

Union-find: each new land cell starts as its own set (count += 1); union with land neighbours, decrementing the count on each successful union. Near O(1) amortised per addition.