← 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?