Bootstrap

leetcode130被围绕的区域

步骤1:问题性质定义

给定一个 m x n 的矩阵 board,矩阵由字符 'X''O' 组成。我们需要捕获所有被 'X' 围绕的 'O' 区域,即将这些 'O' 替换为 'X'。被围绕的 'O' 区域是指这些 'O' 区域完全被 'X' 单元格包围,且该区域不与边缘相连。

输入条件:
  • board 为一个二维矩阵,包含字符 'X''O'
  • mn 为矩阵的行和列,满足 1 <= m, n <= 200
  • board[i][j] 的值为 'X''O'
输出条件:
  • 返回一个二维矩阵,其中所有被 'X' 围绕的 'O' 被替换为 'X',其余的 'O' 保持不变。
限制:
  • mn 的最大值是 200,因此矩阵的最大大小为 40,000 元素,算法需要在合理的时间复杂度内处理。
边界条件:
  • board 中只有 'X''O'
  • board 的尺寸非常小,例如 1x1
  • 边缘上的 'O' 不会被替换。

步骤2:解题思路与步骤分解

问题分析:

我们需要标识出哪些 'O' 是被围绕的。显然,边缘上的 'O' 不会被围绕。最简单的办法是先从边缘的 'O' 开始,使用深度优先搜索(DFS)或广度优先搜索(BFS)将与边缘相连的 'O' 标记为“安全”,剩下的 'O' 就是被围绕的区域,可以被替换为 'X'

解决方案:
  1. 标记安全区域
    • 从四个边缘开始遍历所有 'O',如果发现 'O',就用 DFS 或 BFS 将其与相连的 'O' 都标记为“安全”。
  2. 捕获被围绕的区域
    • 遍历整个矩阵,对于每个没有被标记为“安全”的 'O',将其替换为 'X'
    • 对于标记为“安全”的 'O',保持不变。
算法:
  • DFS/BFS:从四个边缘的 'O' 出发,标记所有连接的 'O'
  • 时间复杂度O(m * n),每个单元格最多访问一次。
  • 空间复杂度O(m * n),用于存储标记和递归栈(DFS)或队列(BFS)。

步骤3:C++代码实现

class Solution {
public:
// DFS实现
void dfs(vector<vector<char>>& board, int i, int j) {
    // 边界条件检查
    if (i < 0 || j < 0 || i >= board. size() || j >= board[0].size() || board[i][j] != 'O') {
        return;
    }
    // 标记当前'O'为安全
    board[i][j] = 'S';  // 'S'表示安全的'O'

    // 向四个方向进行DFS
    dfs(board, i + 1, j);  // 向下
    dfs(board, i - 1, j);  // 向上
    dfs(board, i, j + 1);  // 向右
    dfs(board, i, j - 1);  // 向左
}

void solve(vector<vector<char>>& board) {
    if (board. empty() || board[0].empty()) return;

    int m = board.size();
    int n = board[0].size();

    // 从四个边缘开始DFS
    // 遍历第一行和最后一行
    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++) {
        if (board[i][0] == 'O') dfs(board, i, 0); // 第一列
        if (board[i][n-1] == 'O') dfs(board, i, n-1); // 最后一列
    }

    // 修改被围绕的'O'为'X', 将安全的'O'恢复为'O'
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            if (board[i][j] == 'O') {
                board[i][j] = 'X'; // 被围绕的'O'替换为'X'
            }
            else if (board[i][j] == 'S') {
                board[i][j] = 'O'; // 安全的'O'恢复为'O'
            }
        }
    }
}


};

代码注释:

  1. DFS函数:用于深度优先搜索,找到与边缘相连的 'O',并将它们标记为 'S'(安全)。
  2. 捕获函数 capture:首先从矩阵的四个边缘开始,找到所有与边缘相连的 'O',标记为安全。然后遍历整个矩阵,捕获所有被 'X' 围绕的 'O',并替换为 'X'
  3. 主函数:初始化一个示例 board,调用 capture 函数进行处理,最后输出结果。

步骤4:启发

通过这个问题,我们可以学到以下几个启发:

  • 区域标记技术:通过遍历矩阵边缘,将与边缘相连的区域标记为特殊状态(如‘S’),然后对其他区域进行处理。这种方法在处理图形或网格类问题时非常常见。
  • DFS/BFS应用:DFS 和 BFS 是解决图形问题的常见算法,能够有效标记与特定节点相连的区域,避免重复计算。
  • 边界条件处理:在解决矩阵问题时,需要特别注意边界条件,确保不会越界或错漏。

步骤5:实际应用

这个算法在很多实际应用中有用,尤其是在图像处理、区域划分和边界检测等领域。以下是一个实际应用示例:

应用示例:图像边界检测与区域填充

在图像处理中,我们可能需要处理图像中的封闭区域,例如通过填充算法填充一个被边界围住的区域。类似于这个问题,图像中可能存在“被围绕”的像素区域(例如,某些区域需要被颜色填充,而不想影响边缘区域)。此时,可以使用类似的 DFS/BFS 技术从边缘开始扫描,标记不需要填充的区域,最后进行填充。

实现方法

  1. 对于二值图像(0表示背景,1表示前景),从图像的边缘开始,找到所有与背景相连的前景像素。
  2. 将所有与边缘相连的前景像素标记为“安全”。
  3. 将剩余的前景像素填充为背景颜色。

这种方法被广泛应用于图像编辑软件中,用于实现区域填充、图像剪裁等功能。

;