Fill in the water that does not touch the edge

Graphs Mid-level Python 3.13+ Reviewed By Best Latest Apps

Predict the output

What does this print?

Python 3.13
grid = ["####", "#..#", "##.#", "#.##"]
edge_water = [(r, c) for r in range(4) for c in range(4)
              if grid[r][c] == "." and (r in (0, 3) or c in (0, 3))]
print(edge_water)

Options

Choose an answer, then open Show answer below to check it.

Show answer

Answer: A [(3, 1)]

Right: only the cell at row 3, column 1 is water on the edge.

The middle water at (1, 1), (1, 2) and (2, 2) never touches (3, 1), so it gets filled.

Why not the others?
  • B []. Row 3 is '#.##', so (3, 1) is edge water.
  • C [(1, 1), (1, 2), (2, 2), (3, 1)]. Only edge cells are listed here; the middle ones are not on the border.

30-second answer

Flip the question: find the water that does touch the edge. Search from every edge water cell and mark what it reaches. Everything else that is water must be enclosed, so turn it into land. O(R·C) time and space.

Practise saying it · 45 s. No recording, just a timer

Explain how to fill enclosed regions.

Say your answer out loud, then check which of these points you covered:

  • Search from border water
  • Mark escaping cells
  • Fill the rest

Deep dive

Searching from the border is the same 'start from the boundary' trick as the two-coasts problem.

Checking each region for an edge cell as you flood it also works; the border-first version is simpler.

Returning a new list of strings avoids mutating the caller's data.

Python solution Ran on Python 3.13.5 · mypy --strict
Python 3.13
STEPS = ((1, 0), (-1, 0), (0, 1), (0, -1))


def fill_enclosed(grid: list[str]) -> list[str]:
    rows, cols = len(grid), len(grid[0]) if grid else 0
    todo = [(r, c) for r, row in enumerate(grid)
            for c, ch in enumerate(row)
            if ch == "."
            and not (0 < r < rows - 1 and 0 < c < cols - 1)]
    escapes = set(todo)
    while todo:
        y, x = todo.pop()
        for dy, dx in STEPS:
            ny, nx = y + dy, x + dx
            inside = 0 <= ny < rows and 0 <= nx < cols
            if (inside and grid[ny][nx] == "."
                    and (ny, nx) not in escapes):
                escapes.add((ny, nx))
                todo.append((ny, nx))
    return ["".join("." if (r, c) in escapes else "#"
                    for c in range(len(row)))
            for r, row in enumerate(grid)]

Common mistakes

  • Counting diagonal contact with edge water as an escape when the question uses four directions.
  • Treating a water cell that sits on the edge as enclosed.

Senior take & follow-ups

Explain the flip: mark what escapes, fill the rest.

Follow-up questions

Think of your answer first, then open the hint.

  1. How would you count enclosed regions instead?

    Show hint

    Flood each interior water region and count those that never reach the edge.

  2. What if the map wraps around?

    Show hint

    Then there is no edge, and every region is enclosed unless defined otherwise.

From the author

DSA Master - Data & Algorithms

Free on iPhone and iPad: watch 50+ data structures and algorithms step through animations, run the code in the playground, and try the daily challenge.

Suggest a fix if something here is wrong or out of date.