LeetCode--130被围绕的区域

一、题目与目标

给定一个 m x n 的矩阵 board,元素为 'X''O'

  • 全部 'X' 包围的 'O' 区域要被翻转为 'X'

  • 与边界联通的 'O' 不能 被翻转

要求:原地修改 board


二、解题核心思路

反向思考

  • 真正不能被翻转的是:和边界上的 'O' 连通的所有 'O'

  • 其他 'O' 一定被 'X' 包围,可以翻成 'X'

做法:

  1. 从四条边上所有为 'O' 的格子出发,用 DFS(或 BFS)遍历,把所有和边界连通的 'O' 暂时标记为 '#'

  2. 全图扫描:

    • 遇到 'O':说明它不与边界连通 → 翻成 'X'

    • 遇到 '#':说明它和边界连通 → 还原成 'O'

这样就能区分"能翻转的 O"和"不能翻转的 O"。


三、算法步骤

假设 m 为行数,n 为列数。

  1. 处理左右边界 (第 0 列和第 n-1 列)

    对每一行 i

    • 如果 board[i][0] == 'O',从 (i, 0) 开始 DFS,标记连通块为 '#'

    • 如果 board[i][n - 1] == 'O',从 (i, n-1) 开始 DFS

  2. 处理上下边界 (第 0 行和第 m-1 行)

    对每一列 j

    • 如果 board[0][j] == 'O',从 (0, j) 开始 DFS

    • 如果 board[m - 1][j] == 'O',从 (m-1, j) 开始 DFS

  3. 全表扫描进行翻转

    双重循环遍历整个矩阵:

    • board[i][j] == 'O':翻成 'X'

    • board[i][j] == '#':还原成 'O'


四、代码实现与解析

1. 完整代码

cpp 复制代码
class Solution {
public:
    void solve(vector<vector<char>>& board) {
        // m 表示行数,n 表示列数
        int m = board.size(), n = board[0].size();

        // 1. 处理左右边界
        for (int i = 0; i < m; ++i) {
            if (board[i][0] == 'O') {
                dfs(i, 0, board, n, m);
            }
            if (board[i][n - 1] == 'O') {
                dfs(i, n - 1, board, n, m);
            }
        }

        // 2. 处理上下边界
        for (int j = 0; j < n; ++j) {
            if (board[0][j] == 'O') {
                dfs(0, j, board, n, m);
            }
            if (board[m - 1][j] == 'O') {
                dfs(m - 1, j, board, n, m);
            }
        }

        // 3. 全表扫描,翻转 / 还原
        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:
    // upDown: 行下标,lr: 列下标
    void dfs(int upDown, int lr,
             vector<vector<char>>& board,
             int& n, int& m) {

        // 越界直接返回
        if (upDown < 0 || lr < 0 || lr > n - 1 || upDown > m - 1) return;

        // 只处理 'O'
        if (board[upDown][lr] != 'O') return;

        // 标记为 '#'
        board[upDown][lr] = '#';

        // 四个方向扩展
        dfs(upDown,     lr + 1, board, n, m); // 右
        dfs(upDown,     lr - 1, board, n, m); // 左
        dfs(upDown + 1, lr,     board, n, m); // 下
        dfs(upDown - 1, lr,     board, n, m); // 上
    }
};

说明:mndfs 中按引用传递只是为了少拷贝,按值传也可以,不影响逻辑。


2. 关键点解析

  1. 从边界开始 DFS 而不是从内部

    所有从边界 'O' 出发能走到的 'O' 都是"安全区",临时标记为 '#' 保留。

  2. DFS 的访问条件

    • 先判断越界:upDownlr[0, m-1][0, n-1] 范围内

    • 再判断是否为 'O',不是 'O' 直接返回

  3. 标记与最终翻转的分离

    • DFS 只负责标记 '#'

    • 最后统一遍历一遍矩阵进行 翻转 + 还原

这样保证逻辑清晰、实现简单。


五、时间与空间复杂度

  • 每个格子最多被访问和标记一次

    时间复杂度O(m * n)

  • 递归调用栈最坏深度为 O(m * n)(极端全为 'O' 的情况)

    空间复杂度 :最坏 O(m * n)(递归栈)


六、小结要点

  1. 四条边 上的 'O' 出发,找出所有和边界联通的 'O'

  2. 用临时字符 '#' 标记"边界联通区"

  3. 最后统一遍历:

    • 'O''X'

    • '#''O'

整套解法就是「边界 DFS + 反向思考」模型

相关推荐
lingran__12 分钟前
C++ STL unordered系列(哈希) 底层剖析与模拟实现万字详解 | 基于哈希表,复刻 SGI-STL 泛型哈希容器架构
开发语言·c++·后端·哈希算法·哈希表·泛型编程·unordered系列
布莱克60516 分钟前
理解B+树:原理、特性与应用场景
数据结构·数据库·mysql
叠层归一研究院17 分钟前
如何用程序搭建一个 AGI 种子系统(三):生长如何对接物理与数学宇宙
人工智能·python·算法·机器学习·transformer·agi
鸿芯微控科技22 分钟前
MFC设定流量达不到怎么办?上游供气能力、压差与管路阻力排查
c++·mfc·质量流量控制器·流量不足排查·压差测试·气体流量控制
show43337 分钟前
2026小程序端AI智能优化技术实践:转文字后自动纠错+润色+分段算法分析
人工智能·算法·小程序
郝学胜_神的一滴38 分钟前
C++20 高级编程 003:吃透现代基础语法与标准容器
c++
码匠许师傅43 分钟前
【C++ 面试真题】聊聊 C++ 的关联容器
开发语言·c++·面试
平生不晚1 小时前
在 SVG 体系里画一条任意的线
前端·算法
evans在进步1 小时前
LeetCode 198:打家劫舍——Java 动态规划详解
java·leetcode·动态规划
Hhy_11072 小时前
《C++深度解构02》类和对象(上)——定义规范、内存对齐与 this 指针全解
c语言·开发语言·c++·学习·visual studio