题目描述
给定一个 m x n 的矩阵 board,其中:
'X'表示被围绕的区域。'O'表示开放区域。
任何边界上的 'O' 以及与边界 'O' 相连的 'O',都不会被改变。所有其余的 'O' 需要被替换为 'X'。
解题思路
这道题目是一个 典的 Flood Fill(洪水填充)问题,解决方法可以类比「岛屿问题」。核心思想是 DFS(深度优先搜索)或者 BFS(广度优先搜索)** 找到与边界相连的 'O',将它们标记,最后遍历整个矩阵,将未标记的 'O' 变成 'X',标记的恢复成 'O'。
步骤如下:
-
遍历矩阵的四个边界**,找到所有的
'O',从这些'O'进行 DFS/BFS 标记。 -
在 DFS/BFS 过程中,把所有能到达的
'O'改成临时字符(如'*') ,表示它们不能被包围。 -
第二次遍历矩阵
- 把所有剩余的
'O'变成'X'(因为它们是被包围的)。 - 把所有
'*'变回'O'(因为它们是与边界相连的)。
- 把所有剩余的
class Solution { private static final int[][] DIRS = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
public void solve(char[][] board) {
if (board == null || board.length == 0 || board[0].length == 0) {
return;
}
int m = board.length, n = board[0].length;
// 从边界的 'O' 出发进行 DFS 标记
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 i = 0; i < n; i++) {
if (board[0][i] == 'O') {
dfs(board, 0, i);
}
if (board[m - 1][i] == 'O') {
dfs(board, m - 1, i);
}
}
// 遍历整个矩阵,修改未标记的 'O',恢复 '*'
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (board[i][j] == 'O') {
board[i][j] = 'X';
}
if (board[i][j] == '*') {
board[i][j] = 'O';
}
}
}
}
private void dfs(char[][] board, int i, int j) {
if (i < 0 || i >= board.length || j < 0 || j >= board[0].length || board[i][j] != 'O') {
return;
}
board[i][j] = '*'; // 标记为未被围绕
for (int[] dir : DIRS) {
dfs(board, i + dir[0], j + dir[1]);
}
}
}
- 为什么要用 DFS 而不是 BFS?
- DFS(递归)适合深度遍历,直接从边界
'O'向四个方向递归。 - BFS(队列)也可以解决**,用Queue 逐层遍历,保证更少的递归栈深度,避免栈溢出。
class Solution { private static final int[][] DIRS = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
public void solve(char[][] board) {
if (board == null || board.length == 0) return;
int m = board.length, n = board[0].length;
Queue<int[]> queue = new LinkedList<>();
// 标记边界的 'O'
for (int i = 0; i < m; i++) {
if (board[i][0] == 'O') queue.offer(new int[]{i, 0});
if (board[i][n - 1] == 'O') queue.offer(new int[]{i, n - 1});
}
for (int i = 0; i < n; i++) {
if (board[0][i] == 'O') queue.offer(new int[]{0, i});
if (board[m - 1][i] == 'O') queue.offer(new int[]{m - 1, i});
}
while (!queue.isEmpty()) {
int[] cell = queue.poll();
int x = cell[0], y = cell[1];
if (board[x][y] != 'O') continue;
board[x][y] = '*';
for (int[] dir : DIRS) {
int newX = x + dir[0], newY = y + dir[1];
if (newX >= 0 && newX < m && newY >= 0 && newY < n && board[newX][newY] == 'O') {
queue.offer(new int[]{newX, newY});
}
}
}
// 遍历矩阵,修改 'O' 和 '*' 为最终状态
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (board[i][j] == 'O') board[i][j] = 'X';
if (board[i][j] == '*') board[i][j] = 'O';
}
}
}
}
| 题目 | 题号 | 思路 |
|---|
| 岛屿数量 | 200. Number of Islands | DFS/BFS 计算独立岛屿数 |
|---|
| 腐烂的橘子 | 994. Rotting Oranges | BFS 扩散模拟 |
|---|
| 迷宫最短路径 | 490. The Maze | BFS/DFS 搜索路径 |
|---|
| 被围绕的区域 | 130. Surrounded Regions | 本题 |
|---|
本题属于连通性问题,典型的 DFS/BFS 搜索
- 边界上的
'O'及其联通区域不能变,其余'O'变'X'。 - DFS 适合递归标记,BFS 适合避免栈溢出。
- 本题与岛屿类问题高度相似,可借助经验快速解题。