Number of Islands Solution
Given an m × n grid of '1' (land) and '0' (water), count the number of islands — connected groups of land cells using 4-directional adjacency.
Problem Statement
Given an m × n 2D binary grid where '1' represents land and '0' represents water, return the number of islands. An island is surrounded by water and formed by connecting adjacent lands horizontally or vertically.
Brute Force — Separate Visited Array
Scan every cell. When a land cell that hasn't been visited is found, increment the island count and mark all cells reachable from it as visited using a DFS with a separate boolean[][] visited grid. This correctly counts connected components.
Each DFS call fully explores one connected component (island), marking all cells visited. The outer loop ensures every starting cell is considered. The count of DFS calls from unvisited land cells equals the number of islands.
visited[][] array uses O(m·n) extra space. We can instead mark cells in-place by overwriting '1' with '0' during the flood-fill — no extra grid needed. The input is not explicitly required to be immutable in this problem, so in-place mutation is the standard competitive approach.
| Metric | Value |
|---|---|
| Time | O(m · n) — every cell visited at most once |
| Space | O(m · n) — visited array + O(m · n) call stack worst case |
In-place Flood Fill — O(m·n) time, O(1) extra space
When a land cell '1' is found, immediately sink the entire island by overwriting every connected land cell with '0'. This marks the island as "counted and processed" without a visited array. The number of times the outer loop triggers a sink equals the number of islands.
'1' → '0' mutation — no second map needed.
- Scan all cells in row-major order.
- When
grid[r][c] == '1': increment count, push(r,c)to a queue. - BFS loop: for each cell dequeued, set
grid[r][c] = '0', then enqueue all 4 land neighbors. - Continue outer scan — next island starts when the next unvisited
'1'is encountered.
- "Count connected components in a grid." The signal is a 2D boolean/character grid and the question "how many distinct groups?" Flood-fill from each unvisited component starter directly gives the count.
- Related problems: LC 695 (Max Area of Island — track component size), LC 130 (Surrounded Regions — sink specific components), LC 1020 (Number of Enclaves).
- Both work.
- DFS is simpler to write recursively but risks a stack overflow on very large grids (up to 300×300 = 90,000 cells all land → depth 90,000).
- Iterative BFS avoids the call stack entirely. For interviews, either is acceptable — BFS is safer for production.
Visual Walkthrough
Trace on a 4×5 grid with 3 islands. Each BFS call sinks one island.
Code — Java & Python
Complexity Analysis
| Approach | Time | Space | Trade-off |
|---|---|---|---|
| DFS with visited array | O(m · n) | O(m · n) | Preserves input but uses extra O(m·n) space |
| Union-Find | O(m · n · α(m·n)) | O(m · n) | Generalizes to dynamic connectivity; heavier constant |
| BFS in-place ← optimal | O(m · n) | O(min(m,n)) queue | Mutates input — confirm with interviewer; otherwise use visited array |
- In BFS, the queue holds at most one BFS frontier at a time.
- For a grid, the largest possible frontier is a diagonal wave across the grid — bounded by
min(m, n)cells. - In contrast, a recursive DFS on an all-land grid can go m·n levels deep, overflowing the call stack.
Edge Cases & Pitfalls
| Case | Input | Why It Matters |
|---|---|---|
| All water | All '0' | Outer scan never finds '1'. Returns 0 correctly. |
| All land | All '1' | First cell starts BFS that sinks everything. Returns 1. |
| 1×1 land | [["1"]] | Single-cell island. BFS starts and immediately finishes. Returns 1. |
| 1×n row | [["1","0","1","1"]] | Two islands. BFS for each connected land segment. |
| Large grid (300×300) | All '1' | 90,000 cells — BFS queue approach safe; recursive DFS would overflow the stack. |
| Sinked too late | any | If you set grid[r][c]='0' when dequeuing instead of when enqueuing, the same cell can be enqueued multiple times, causing redundant BFS work. |
grid[nr][nc] = '0' immediately when enqueuing — this is the standard BFS "mark on enqueue" pattern that prevents duplicate entries.