Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Coding Interview Patterns  Module 20 – Graph patterns: traversal

Number of islands: flood fill and border regions

Count the islands of a grid with one flood fill per island, avoid recursion limits on long islands, and find the regions that can reach the border.

  • Intermediate
  • 35 minutes
  • Examples run with Python 3.14.8, Pyodide 314.0.7, Node.js 24.21.0, quickjs 0.32.0, Java 25, Clang 21.0.0 and Go 1.27.1
  • By MySmartCoPilot
Free intro, Pro: 9 of 35 minutes free
Free: The problem: islands on a survey map · The brute force: relabel until nothing changes · What to notice. With a pass: the other 10 sections and 3 interview answers, about 26 minutes.

What you will learn

  • Count the connected regions of a grid with one flood fill per region in O(rows × cols)
  • Implement the flood fill with a queue or an explicit stack instead of deep recursion
  • Find the cells that can reach the border by searching inwards from the edge
  • Identify distinct island shapes with a canonical key
  • Reproduce the common bugs of grid searches on the smallest maps that break them

Before you start

What you’ll learn · Before you start

What you will learn

  • Count the connected regions of a grid with one flood fill per region in O(rows × cols)
  • Implement the flood fill with a queue or an explicit stack instead of deep recursion
  • Find the cells that can reach the border by searching inwards from the edge
  • Identify distinct island shapes with a canonical key
  • Reproduce the common bugs of grid searches on the smallest maps that break them

Before you start

On this page

Number of islands asks how many separate groups of land a grid holds, where two land cells belong together when a chain of land cells sharing sides joins them. Each island is a connected component of the grid’s graph, so the count is the number of searches it takes to mark all the land: one flood fill from every land cell that no earlier search reached. Grids show up in coding rounds as maps, boards, images and seating plans, and the same fill also answers which regions can reach the border.

The problem: islands on a survey map

The problem

A survey returns a map as rows strings of cols characters: '#' is land and '.' is water. Two land cells are on the same island when you can walk from one to the other over land, one step at a time to a cell that shares a side. Touching at a corner does not count. Return the number of islands. Limits: 1 ≤ rows, cols ≤ 1,000.

Three examples:

  1. The 5 × 8 survey map in the diagram has 5 islands. Islands C and E touch only at a corner, so they stay apart.
  2. A map of water only, such as three rows of ...., has 0 islands.
  3. The single row #.#.## has 3 islands: two single cells and a pair.
The 5 by 8 survey map with its land cells lettered A to E by island; islands C and E touch only at one corner.0123456701234AABABBCBDCCCDEDD

The survey map, every land cell lettered with its island

Text description of the diagram

The map has 5 rows, numbered 0 to 4 from the top, and 8 columns, numbered 0 to 7 from the left. Land cells are shaded and carry the letter of their island; water cells are plain.

  1. Island A, 3 cells: row 0, columns 0 and 1, and row 1, column 0.
  2. Island B, 4 cells: row 0, column 4; row 1, columns 4 and 5; row 2, column 5.
  3. Island C, 4 cells: row 2, column 2, and row 3, columns 1, 2 and 3.
  4. Island D, 4 cells: rows 2 and 3, column 7, and row 4, columns 6 and 7.
  5. Island E, 1 cell: row 4, column 4.

A dashed circle marks the corner where island C, at row 3, column 3, meets island E, at row 4, column 4. The two cells touch only diagonally, so they share no side and stay separate islands: the map has 5 islands. If diagonal contact counted, C and E would merge and the count would be 4.

The brute force: relabel until nothing changes

A method that needs no graph idea: give every land cell its own label, then sweep the map again and again, letting each land cell take the smallest label among itself and its land neighbours. When a sweep changes nothing, each island holds one label, so the answer is the number of distinct labels. It is correct, and on the survey map it takes 3 sweeps. The run then tries winding islands, full rows joined at alternate ends:

Relabelling sweeps on the survey map and on winding islands Python · brute/labels_brute.py
"""Islands by relabelling: every land cell takes the smallest label among itself and its land neighbours, sweep after
sweep, until a sweep changes nothing. Correct, but a winding island needs a sweep for almost every cell it has."""

SURVEY = [
    "##..#...",
    "#...##..",
    "..#..#.#",
    ".###...#",
    "....#.##",
]


def islands_by_relabelling(grid):
    rows, cols = len(grid), len(grid[0])
    label = [[r * cols + c if grid[r][c] == "#" else -1 for c in range(cols)] for r in range(rows)]
    sweeps = 0
    changed = True
    while changed:
        changed = False
        sweeps += 1
        for r in range(rows):
            for c in range(cols):
                if label[r][c] < 0:
                    continue
                best = label[r][c]
                for dr, dc in ((-1, 0), (1, 0), (0, -1), (0, 1)):
                    nr, nc = r + dr, c + dc
                    if 0 <= nr < rows and 0 <= nc < cols and 0 <= label[nr][nc] < best:
                        best = label[nr][nc]
                if best < label[r][c]:
                    label[r][c] = best
                    changed = True
    count = len({x for row in label for x in row if x >= 0})
    return count, sweeps


def snake(k):
    """A k x k map holding one island that winds back and forth: full rows joined at alternate ends."""
    grid = []
    for r in range(k):
        if r % 2 == 0:
            grid.append("#" * k)
        elif r % 4 == 1:
            grid.append("." * (k - 1) + "#")
        else:
            grid.append("#" + "." * (k - 1))
    return grid


count, sweeps = islands_by_relabelling(SURVEY)
print(f"Survey map, 5 x 8: {count} islands after {sweeps} sweeps")
print()
print("Winding islands:")
print("    k  land cells  sweeps  cells read")
for k in (8, 16, 32, 64):
    g = snake(k)
    count, sweeps = islands_by_relabelling(g)
    land = sum(row.count("#") for row in g)
    print(f"{k:>5} {land:>11,} {sweeps:>7,} {sweeps * k * k:>11,}   islands: {count}")

Output

Survey map, 5 x 8: 5 islands after 3 sweeps

Winding islands:
    k  land cells  sweeps  cells read
    8          36      16       1,024   islands: 1
   16         136      62      15,872   islands: 1
   32         528     250     256,000   islands: 1
   64       2,080   1,010   4,136,960   islands: 1

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 labels_brute.py

The labels flow with the sweep along some rows and against it along others, one cell per sweep. So a winding island needs about k²/4 sweeps on a k × k map: 1,010 at k = 64, which read 4,136,960 cells. At 1,000 × 1,000 that is about 250,000 sweeps of a million cells, 2.5 × 10¹¹ cell visits of four neighbour checks each: hours, even in C++.

What to notice

An island is a set of cells that a single search reaches from any one of its cells. So start a flood fill from the first unmarked land cell, mark everything it reaches, add 1 to the count, and continue the scan. Each cell is marked once and looked at from its four neighbours, so the whole count is O(rows × cols), about 5 million steps at the limits. Border regions follow the same idea in reverse: one search started from every border cell at once marks everything that can reach the edge.

Flood fill: one search per island Pro: opens with a Pro, Premium or Ultimate pass

In this part:

  • Why every island is counted exactly once: the invariant
    • The code in five languages
  • Deep islands: recursion that runs out of stack
  • Searching inwards from the edge
    • Lakes: water that cannot reach the edge
    • Cells that drain to both coasts
  • Distinct island shapes
  • Variants: corner contact, areas, perimeters and islands that grow
  • Edge cases and common bugs
  • Exercise: land that cannot reach the edge
    • Count the land cells that cannot reach the edge
  • A practice set with answers
  • Check yourself
  • Interview questions
    • Why does starting a flood fill from every unmarked land cell count each island exactly once?
    • A recursive island counter passes every test, then crashes on a 1,000 × 1,000 satellite map whose land is one long winding strip. Explain the crash, estimate the depth, and rewrite the fill. How much memory does your version need in the worst case?
    • A 1,000 × 1,000 map starts as water and receives 200,000 updates of the form "cell (r, c) is now land". After each update the app must report the number of islands. What do you use, what does one update cost, and what happens when the same cell is reported twice?
    • A drone streams a map row by row: a million rows of 10,000 cells, far too much to store. Count the islands while reading, keeping only about two rows in memory. How do you avoid counting one island twice when two of its parts only meet many rows later?
  • Key takeaways

8 runnable examples (C++, Go, Java, JavaScript, Python) · 1 exercise with sample tests · 3 interview answers · about 22 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.