Surrounded Regions(被围绕的区域)解析

63 阅读3分钟

题目描述

给定一个 m x n 的矩阵 board,其中:

  • 'X' 表示被围绕的区域。
  • 'O' 表示开放区域。

任何边界上的 'O' 以及与边界 'O' 相连的 'O',都不会被改变。所有其余的 'O' 需要被替换为 'X'

解题思路

这道题目是一个 典的 Flood Fill(洪水填充)问题,解决方法可以类比「岛屿问题」。核心思想是 DFS(深度优先搜索)或者 BFS(广度优先搜索)** 找到与边界相连的 'O',将它们标记,最后遍历整个矩阵,将未标记的 'O' 变成 'X',标记的恢复成 'O'

步骤如下:

  1. 遍历矩阵的四个边界**,找到所有的 'O',从这些 'O' 进行 DFS/BFS 标记。

  2. 在 DFS/BFS 过程中,把所有能到达的 'O' 改成临时字符(如 '*') ,表示它们不能被包围。

  3. 第二次遍历矩阵

    • 把所有剩余的 '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]);
    }
}

}

  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 IslandsDFS/BFS 计算独立岛屿数
腐烂的橘子994. Rotting OrangesBFS 扩散模拟
迷宫最短路径490. The MazeBFS/DFS 搜索路径
被围绕的区域130. Surrounded Regions本题

本题属于连通性问题,典型的 DFS/BFS 搜索

  1. 边界上的 'O' 及其联通区域不能变,其余 'O''X'
  2. DFS 适合递归标记,BFS 适合避免栈溢出。
  3. 本题与岛屿类问题高度相似,可借助经验快速解题。