← DSA Atlas
Dedicated problem page · #130

Surrounded Regions

MediumGraph DFS and BFSBorder-guarded flood fillDFS from the grid border
Solve on LeetCode ↗
130
MediumGraph DFS and BFSDFS from the grid borderBorder-guarded flood fill

Surrounded Regions

Given an m x n board of 'X' and 'O', capture all regions that are 4-directionally surrounded by 'X' by flipping every 'O' in such a region to 'X'. An 'O' region is safe only if it touches the board's border.

Open official problem prompt ↗
In plain English

Flip only the O regions that are completely enclosed by X, leaving border-connected O regions untouched.

Picture it like this

Think of the border as the only exit from a flooded building; any water (O) that can trace a path to an exit stays, and any water trapped in an inner room gets sealed off (turned to X).

Example
Input
board = [["X","X","X","X"],["X","O","O","X"],["X","X","O","X"],["X","O","X","X"]]
Output
[["X","X","X","X"],["X","X","X","X"],["X","X","X","X"],["X","O","X","X"]]
Why
The inner O region is fully surrounded and captured; the bottom-row O at (3,1) touches the border so it survives.
Constraints
m == board.lengthn == board[i].length1 <= m, n <= 200board[i][j] is 'X' or 'O'
Pattern lesson

See the pattern, then code

Border-guarded flood fill
Recognition clue

Regions are captured unless they reach the edge; the escape hatch being the border is the signal to flood fill inward from the border instead of from the interior.

↗
Graph DFS and BFS

Connected components, grids, reachability, or unweighted shortest paths.. It is easier to find the O's that are safe than the ones that are captured: any O connected to a border O escapes, so mark those first, then flip everything else.

New words, made simpleKnow these before the algorithm
Border cell
A cell in the first or last row or column.
Safe region
A group of O's connected to at least one border O.
Sentinel marker
A temporary symbol ('#') used to remember safe cells during the scan.
Approaches from first idea to best ideaCompare the trade-offs
ApproachHow it thinksCost
Flood fill from every interior O

Repeatedly re-testing regions for border contact is redundant work.

For each interior O region, test whether it reaches the border.

Time O((m*n)^2)Space O(m*n)
The rule we keep true

Invariant

After the border DFS, a cell is '#' if and only if it is an O connected to the border, so all remaining O's are captured.

Why this is correct

Reasoning

A region is captured exactly when it has no border O, which is the negation of being reachable from the border; marking safe cells first turns the flip step into a simple relabeling.

The algorithm in three movesSay these aloud before coding
1From every 'O' on the four borders, DFS and temporarily mark connected O's as safe ('#')

border DFS marks safe O's as '#'

2Scan the whole board

interior O at (1,1),(1,2),(2,2) stay 'O'

3Flip any remaining 'O' (not border-connected) to 'X'

flip inner O->X, restore #->O

4Restore every '#' back to 'O'

Visual trace

Follow the data, one decision at a time

Input snapshotHighlighted cells are involved in this example
O0
O1
O2
X3
1 · Readborder cells
2 · AskAny O on the edge?
3 · Update state(3,1) is O on bottom row
4 · ResultDFS marks (3,1) as '#'
Key takeaway

Border-touching O's are marked safe; interior O's with no border path get captured.

Code walkthrough

Read the solution in small chunks

Python 3

Do not memorize the whole program. Connect each group of lines to one job in the algorithm.

  1. 1
    Lines 6-14Safe-marking DFS

    Spreads through connected O's, marking each with the sentinel '#'.

  2. 2
    Lines 16-19Launch from the border

    Only border O's seed the DFS, so exactly the escapable regions get marked.

  3. 3
    Lines 21-26Flip then restore

    Unmarked O's are captured to 'X'; sentinels are restored to 'O'.

Make it stick

Edge cases, mistakes, and one self-check

E

Edge cases to test

  • Board with all X and no O leaves it unchanged
  • A single row or column where every O touches the border
  • All O's connected to the border (nothing captured)
  • 1x1 board
!

Common beginner mistakes

  • Starting DFS from interior cells instead of the border
  • Forgetting to restore the sentinel marker back to 'O'
  • Flipping in place before marking safe cells, which destroys the information needed
  • Off-by-one when identifying border rows and columns
Check your understanding

Why is it easier to mark safe (border-connected) O's than to directly find captured ones?