Graphs — Visual Learning

Number of Islands —
A grid is just a graph in disguise.

Every unvisited land cell you find is the seed of a new island — flood-fill outward from it with BFS or DFS, marking every connected land cell visited, and count how many times you had to start a fresh flood fill. It's BFS/DFS with 4 neighbors (up/down/left/right) instead of a graph's adjacency list. Watch the flood fill spread on LearnBug and see each island claimed in turn.

O(rows×cols)Time complexity
O(rows×cols)Space complexity
PythonLanguage

What is the Number of Islands problem?

Given a grid of "1" (land) and "0" (water), count the number of islands — groups of land cells connected horizontally or vertically. Scan every cell; whenever you find unvisited land, that's a brand new island, so flood-fill outward from it to mark the whole connected group visited, then keep scanning.

Why visualization helps

The insight that unlocks this problem is realizing a grid is a graph — each cell is a node, and its 4 neighbors are its edges. LearnBug highlights the flood fill spreading cell by cell and shows exactly when the scan finds a fresh, unvisited land cell that starts a new island — making that graph structure visible on a shape everyone already recognizes.

YouTube — Number of Islands Explained Visually
📺 Drop your YouTube embed here
LearnBug — flood fill spreading across a grid
🖼 Add a LearnBug screenshot here
Grid as Graph

Everything you already know about graphs, applied to a grid

Cells are nodes, adjacency is edges

Each grid cell connects to up to 4 neighbors (up, down, left, right) — that's the entire "adjacency list," computed from coordinates instead of stored explicitly.

4-directional

BFS or DFS both work

The flood fill can use either — a queue (BFS) or recursion/stack (DFS). Same result: every connected land cell gets marked in one flood fill.

Either works

Counting connected components

This is exactly the "count connected components" pattern — number of provinces, friend circles, and network clusters are the same problem elsewhere.

Connected components
Walkthrough

Islands on a 3×3 grid: [1,1,0] / [0,1,0] / [0,0,1]

1

Scan hits (0,0) — unvisited land. Start a new island, flood fill outward

This is the first land cell found while scanning row by row. It's unvisited, so it's the seed of island #1. BFS from here spreads to every connected land cell.

(0,0)seed
(0,1)
(1,1)
(2,2)
Islands found: 1  |  Flood fill queue: [(0,0)]
2

Flood fill spreads to (0,1) and (1,1) — both connected to the seed

(0,1) is land and adjacent to (0,0) — visit it, and it in turn connects to (1,1), also land. All three get marked visited as part of the same island.

(0,0)
(0,1)visited
(1,1)visited
(2,2)
Island #1: [(0,0), (0,1), (1,1)] — flood fill complete, queue empty
3

Scan continues, skips visited/water cells, hits (2,2) — unvisited land

(1,0), (2,0), (2,1) are all water. (2,2) is land and not connected to island #1 (no shared edge with any visited cell), so it starts island #2.

(0,0)
(0,1)
(1,1)
(2,2)seed #2
Islands found: 2  |  (2,2) has no land neighbors — flood fill is just itself
4

Scan finishes — every cell visited or water

No unvisited land cells remain, so the outer scan loop ends.

Return: 2 islands ✓ [(0,0),(0,1),(1,1)] and [(2,2)]

Python Code

Grid BFS flood fill

PythonBFS flood fill — O(rows×cols) time and space
grid = [
    ["1", "1", "0"],
    ["0", "1", "0"],
    ["0", "0", "1"],
]
rows, cols = len(grid), len(grid[0])
visited = set()

def bfs(r, c):
    queue = [(r, c)]
    visited.add((r, c))
    while queue:
        row, col = queue.pop(0)
        for dr, dc in [(-1,0),(1,0),(0,-1),(0,1)]:
            nr, nc = row + dr, col + dc
            if (0 <= nr < rows and 0 <= nc < cols
                    and (nr, nc) not in visited and grid[nr][nc] == "1"):
                visited.add((nr, nc))
                queue.append((nr, nc))

islands = 0
for r in range(rows):
    for c in range(cols):
        if grid[r][c] == "1" and (r, c) not in visited:
            bfs(r, c)          # claims the whole connected island
            islands += 1

print(islands)

Complexity Notes

TimeO(rows × cols)Every cell is visited by the scan and enters the flood fill at most once
SpaceO(rows × cols)Visited set (or recursion stack for DFS) can hold every cell in the worst case
4-directional vs 8Check the problemSome variants also count diagonal neighbors as connected — read the problem statement carefully
In-place alternativeMutate the gridInstead of a visited set, some solutions overwrite visited "1"s with "0" directly — saves the extra set's space

Frequently asked questions

Should I use BFS or DFS for the flood fill?

Either works and gives the same island count — this is a "visit every connected node" problem, not a shortest-path problem, so BFS's shortest-path guarantee isn't relevant here. DFS (recursive or with an explicit stack) is often slightly shorter to write; BFS avoids recursion-depth issues on very large islands.

Do I need a separate visited set?

Not necessarily — a common space-saving trick is to overwrite visited land cells directly in the grid (change "1" to "0" once visited), which avoids allocating a separate set entirely. This lesson uses a visited set for clarity, but mutating the grid in place is equally valid and commonly asked about in interviews.

What if diagonal cells should count as connected?

Add the four diagonal direction offsets — (-1,-1), (-1,1), (1,-1), (1,1) — to the neighbor list alongside the four cardinal directions. Everything else about the algorithm stays the same; only the definition of "adjacent" changes.

How does this relate to "number of provinces" or "friend circles"?

Same underlying pattern — counting connected components — just on a different graph representation. Number of Islands uses an implicit grid graph; Number of Provinces typically gives you an explicit adjacency matrix. The flood-fill/count logic is identical.

Watch the flood fill claim each island

Paste your grid BFS/DFS into LearnBug and see every cell visited live.

Open Playground →