Number of Islands
Each unvisited land cell launches a flood fill that sinks its whole island.
Scan and Flood Fill
Problem
You are given a rectangular grid containing land cells marked 1 and water cells marked 0. Count the number of islands, where an island is a group of horizontally or vertically adjacent land cells; diagonal contact does not connect cells. Return the total number of distinct islands.
Examples
Input: grid = [["1","1","0","0"],["1","0","0","1"],["0","0","1","1"],["0","0","0","0"]]
Output: 2
Input: grid = [["1","0","1"],["0","1","0"],["1","0","1"]]
Output: 5
The Goal
Count the islands in a grid of "1" (land) and "0" (water). An island is land cells joined up, down, left or right. Cells that only touch at a corner don't connect.
Scan the grid in reading order. The first land cell of an island that the scan meets starts a flood fill, which reaches every cell of that island. So each island is counted once, when the scan finds its first cell.
One flood fill, one island
Land the scan reaches before any flood fill has starts a new island. Every other land cell belongs to an island already counted.
Count flood fills, not land cells.
Key Idea: Mark a Cell When You Queue It
A flood fill keeps a queue of cells to visit and a seen set. Mark a cell seen the moment you queue it, not when you pop it. Then no cell is queued twice, even when two of its neighbors both reach it.
Later, when the scan passes a cell that's already seen, it skips it. That island is already counted.
A cell is marked seen as it's queued.
No cell is queued twice.
The Algorithm
The outer loops find islands. The while loop drains one island's queue.
from collections import deque
def num_islands(grid):
rows, cols = len(grid), len(grid[0])
seen = set()
islands = 0
for r in range(rows):
for c in range(cols):
if grid[r][c] != "1" or (r, c) in seen:
continue
islands += 1
seen.add((r, c))
queue = deque([(r, c)])
while queue:
row, col = queue.popleft()
for nr, nc in ((row + 1, col), (row - 1, col), (row, col + 1), (row, col - 1)):
if 0 <= nr < rows and 0 <= nc < cols and grid[nr][nc] == "1" and (nr, nc) not in seen:
seen.add((nr, nc))
queue.append((nr, nc))
return islandsA depth-first fill swaps the queue for a stack or recursion and counts the same islands.
| Approach | How it finds an island | Extra space |
|---|---|---|
| BFS | Drains a queue from the first cell | O(R · C) |
| DFS | Recursion or a stack from the first cell | O(R · C), as deep as the island |
| Union-Find | Merges neighboring land, then counts groups | O(R · C) |
Walkthrough
Run it on the 4 × 4 grid. The scan meets (0,0) first: islands = 1. Its fill queues (1,0) and (0,1), and neither has new land beside it, so island 1 is three cells.
The scan skips (0,1) and (1,0), already seen. At (1,3) it finds fresh land: islands = 2. That fill reaches (2,3), then (2,2). Every other cell is water or already seen, so the answer is 2.
Checkpoint · predict the next step
Step 11 of 34 on the stage: Scan (0,1): land, but island 1's flood fill already reached it. Skip it.
scan at (0, 1) · queue = [] · islands 1
Pitfalls
- Mark cells when you queue them. Marking on pop lets a cell be queued twice when two neighbors reach it.
- Check the bounds before you read
grid[nr][nc]. - Diagonal land doesn't connect:
["101","010","101"]is 5 islands. - All water is 0 islands, and all land is 1.
- Recursive DFS on a long, thin island can pass Python's recursion limit. The queue can't.
When should a cell be marked seen?
Another Way: Union-Find
Union-Find reaches the same count without a flood fill. Start with every land cell in a group of its own. For each pair of neighboring land cells, merge their groups. The answer is the number of groups left.
The example has six land cells and four neighboring pairs, and every merge joins two groups, so 2 are left.
What does one flood fill count?
1 / 2
Complexity
Say the grid has R rows and C columns. The scan reads each cell once. Each land cell is queued once and checks four neighbors, so the fills add O(R · C) more. Time is O(R · C).
The seen set and the queue can each hold every cell of an all-land grid, so space is O(R · C) too.
Scan plus flood fill
- Scan every cellHere n = R · C.dominantO(n)
- Fill each islandEach land cell is queued once and checks 4 neighbors.dominantO(n)
- Seen set and queueAn all-land grid fills both.dominantO(n)
| n | 10 | 100 | 1,000 | 10,000 |
|---|---|---|---|---|
| O(n) | 10 | 100 | 1K | 10K |
Linear in the grid: every cell has to be read once anyway.
In short
Scan the grid; when you hit unvisited land, increment the count and DFS/BFS to mark every connected land cell visited (flood fill). Union-Find is an alternative that merges adjacent land cells and counts components.
Common mistake
Not marking cells visited (or not marking them immediately), causing recounting or infinite recursion.