Browse curriculum

Surrounded Regions

Capture regions that are fully surrounded by 'X'.

Examples

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']]
Explain:

The 'O' at the bottom is connected to the border, so it's not surrounded. The center island is surrounded and flipped.

Problem Understanding

Given an m x n board containing 'X' and 'O', capture all regions that are 4-directionally surrounded by 'X'.
A region is captured by flipping all 'O's into 'X's in that surrounded region.

Key Insight: An 'O' is NOT surrounded if connects to an 'O' on the boundary.

Algorithm Strategy (Reverse Thinking)

Instead of searching for surrounded regions (hard), let's search for Unsurrounded regions (easy).

  1. Border Check: Any 'O' on the border is safe. Any 'O' connected to a border 'O' is also safe.
  2. Phase 1 (Mark Safe): Call DFS on every cell of the 4 borders. DFS returns at once unless the cell is an 'O', and marks every 'O' it reaches as 'T' (temporarily safe).
  3. Phase 2 (Flip): Iterate over the entire grid.
    • If cell is 'O' (Unmarked) -> It's trapped. Flip to 'X'.
    • If cell is 'T' (Marked) -> It's safe. Flip back to 'O'.

Visualization

Two passes. First, DFS runs from every border cell — each row's left and right cell, then each column's top and bottom cell — and marks every 'O' it reaches as 'T'. Corner cells are called twice, once from their row and once from their column; when a corner is an 'O', the second call finds it already 'T' and returns. Then one pass over the whole board captures every 'O' still unmarked (red) and restores every 'T' to 'O' (green).

Dry Run

Board:

X O X
X O X
X X X
Step Pass Call or cell Action
1 Border rows dfs(0,0), dfs(0,2), dfs(1,0), dfs(1,2), dfs(2,0), dfs(2,2) Each cell is 'X' — every call returns.
2 Border columns dfs(0,0), dfs(2,0) 'X' — return.
3 Border columns dfs(0,1) 'O' — mark 'T'. Call down.
4 inside dfs(0,1) dfs(1,1) 'O' — mark 'T'. Down (2,1) is 'X', up (0,1) is 'T', right (1,2) and left (1,0) are 'X' — all return.
5 back in dfs(0,1) up, right, left (-1,1) is outside, (0,2) and (0,0) are 'X' — return.
6 Border columns dfs(2,1), dfs(0,2), dfs(2,2) 'X' — return.
7 Flip (0,1), (1,1) 'T' — restore to 'O'.
8 Flip every other cell 'X' — keep.

No 'O' was left unmarked, so nothing is captured: the column of 'O's escapes through the top edge.

Edge Cases & Common Mistakes

  • No 'O' on Border: If all border cells are 'X', ANY 'O' inside is trapped. They will all be flipped.
  • All 'O' Board: If grid is full of 'O's, they are all connected to border. None flipped.
  • Small Grid: 1x1 or 2x2 grid cannot have any captured region (all cells touch border).

Solution

Using the Border DFS technique.

Surrounded Regions Code
1var solve = function(board) {
2 const rows = board.length, cols = board[0].length;
3
4 function dfs(r, c) {
5 if (r < 0 || r >= rows || c < 0 || c >= cols || board[r][c] !== 'O') {
6 return;
7 }
8 board[r][c] = 'T';
9 dfs(r + 1, c);
10 dfs(r - 1, c);
11 dfs(r, c + 1);
12 dfs(r, c - 1);
13 }
14
15 for (let r = 0; r < rows; r++) {
16 dfs(r, 0);
17 dfs(r, cols - 1);
18 }
19 for (let c = 0; c < cols; c++) {
20 dfs(0, c);
21 dfs(rows - 1, c);
22 }
23
24 for (let r = 0; r < rows; r++) {
25 for (let c = 0; c < cols; c++) {
26 if (board[r][c] === 'O') {
27 board[r][c] = 'X';
28 } else if (board[r][c] === 'T') {
29 board[r][c] = 'O';
30 }
31 }
32 }
33};

The approach, step by step

  1. Mark from the border

    Call dfs on every border cell; dfs marks each reachable 'O' as 'T'.

  2. Capture

    In a final pass, flip every remaining 'O' to 'X'.

  3. Restore

    In the same pass, flip every 'T' back to 'O'.

Frequently asked questions

Why start from the border instead of the surrounded regions?

A region is safe exactly when it touches the border. Starting from the border finds every safe 'O' in one sweep; anything left unmarked must be surrounded.


Why mark safe cells with a temporary 'T'?

The final pass needs to tell three kinds of cell apart: 'X', safe 'O', and trapped 'O'. The 'T' separates the safe ones without any extra grid.


Can a cell on the border ever be captured?

No. Every border 'O' is the start of a DFS, so it is always marked 'T' and restored.

Applying for software engineering roles? Free, no sign-up:

AI resume checker — match your resume to the job description