Surrounded Regions
Problem link: https://leetcode.com/problems/surrounded-regions/
Problem Statement
Given an m x n matrix 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. An 'O' is not captured if it is on the edge or connected to an 'O' on the edge.
Input
An m x n board of characters ('X' and 'O').
Output
Void. The board must be modified in-place.
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"] ]
Explanation
The 'O' at (3,1) is on the boundary, so it stays 'O'. All other 'O's are internal and surrounded by 'X's, so they are flipped to 'X'.
Brute Force
Intuition
For every 'O' encountered, run a DFS to check if it can reach the boundary. If the traversal finishes without touching an edge, mark that whole region for flipping.
Approach
- Iterate through every cell $(i, j)$.
- If
board[i][j] == 'O', start a DFS/BFS. - Track if any cell in this cluster is on the boundary.
- If not, re-traverse the cluster to flip to 'X'.
Optimal Solution
Intuition
Reverse the thinking: Identify which 'O's are NOT surrounded. An 'O' is safe if it is on the boundary or connected to a boundary 'O'.
Approach
- Boundary Scan: Loop through the first/last rows and columns.
- Marking: For every boundary 'O', trigger a DFS to mark it and its connected neighbors as '#'.
- Transformation: Traverse the entire grid:
- If 'O' -> Change to 'X' (it was surrounded).
- If '#' -> Change to 'O' (it was safe).
Code (Java)
class Solution {
public void solve(char[][] board) {
if (board == null || board.length == 0) return;
int m = board.length, n = board[0].length;
for (int i = 0; i < m; i++) {
if (board[i][0] == 'O') dfs(board, i, 0);
if (board[i][n - 1] == 'O') dfs(board, i, n - 1);
}
for (int j = 0; j < n; j++) {
if (board[0][j] == 'O') dfs(board, 0, j);
if (board[m - 1][j] == 'O') dfs(board, m - 1, j);
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (board[i][j] == 'O') board[i][j] = 'X';
else if (board[i][j] == '#') board[i][j] = 'O';
}
}
}
private void dfs(char[][] board, int r, int c) {
if (r < 0 || r >= board.length || c < 0 || c >= board[0].length || board[r][c] != 'O') return;
board[r][c] = '#';
dfs(board, r + 1, c);
dfs(board, r - 1, c);
dfs(board, r, c + 1);
dfs(board, r, c - 1);
}
}
Complexity Analysis
Every cell is processed a constant number of times. Space is $O(M \cdot N)$ for the recursion stack in the worst case where many 'O's are connected.
Quick Revision (Brute Force)
- DFS from every internal 'O' to see if it reaches the edge.
- Redundant and slow: $O((M \cdot N)^2)$
Quick Revision (Optimal)
- Boundary DFS Strategy.
- Identify 'Safe' O's first starting from edges.
- Anything not marked Safe is surrounded.
- O(M*N) time complexity.