【每天学习一点算法 2026/05/15】被围绕的区域

每天学习一点算法 2026/05/15

题目:被围绕的区域

给你一个 m x n 的矩阵 board ,由若干字符 'X' 和 'O' 组成,捕获 所有 被围绕的区域:

连接:一个单元格与水平或垂直方向上相邻的单元格连接。

区域:连接所有 'O' 的单元格来形成一个区域。

围绕:如果一个区域中的所有 'O' 单元格都不在棋盘的边缘,则该区域被包围。这样的区域 完全 被 'X' 单元格包围。

通过 原地 将输入矩阵中的所有 'O' 替换为 'X' 来 捕获被围绕的区域。你不需要返回任何值。

这道题的思路还是很简单的,首先遍历矩阵,遇到 'O' 时,开始递归遍历完所有相邻的 'O',如果过程没有碰到边界就将这些 'O' 替换成 'X',否则就不做操作。

typescript 复制代码
function solve(board: string[][]): void {
  const visited = new Set<string>(); // 存储访问过的位置
  const oset = new Set<string>(); // 存储当前遍历相邻 'O' 的位置
  let isBorder = false; // 是否被围绕的标识

  // DFS辅助函数
  const dfs = (row: number, col: number) => {
    const key = `${row},${col}`; // 当前元素位置信息
    if (visited.has(key)) return; // 避免重复访问元素
	// 添加位置信息
    visited.add(key); 
    oset.add(key);
    
    // 边界判断:触达边界则标记
    if (row === 0 || row === board.length - 1 || col === 0 || col === board[0].length - 1) {
      isBorder = true;
    }

    // 上下左右递归
    const dirs = [[-1,0], [1,0], [0,-1], [0,1]];
    for (const [dr, dc] of dirs) {
      const r = row + dr;
      const c = col + dc;
      if (board[r]?.[c] === 'O') dfs(r, c);
    }
  };

  // 主遍历
  for (let i = 0; i < board.length; i++) {
    for (let j = 0; j < board[0].length; j++) {
      if (board[i][j] === 'X' || visited.has(`${i},${j}`)) continue;
      
      isBorder = false;
      oset.clear();
      dfs(i, j);

      // 非边界连通区域全部改为X
      if (!isBorder) {
        oset.forEach(loc => {
          const [r, c] = loc.split(',').map(Number);
          board[r][c] = 'X';
        });
      }
    }
  }
}

我们其实可以很容易的发现,所有 'O' 相连的区域,只有两种情况:触碰到边界 和 未触碰到边界(被 'X' 包围),那我们完全可以先找到边界上的 'O',递归出他们相邻的 'O',并将他们修改成另外的标识,比如 'C',最终再遍历整个 board 将 'C' 设成 'O', 'O' 设成 'X' 即可。

typescript 复制代码
function solve(board: string[][]): void {
  // DFS辅助函数
  const dfs = (row: number, col: number) => {
    // 将所有边界相邻的 'O' 标记为 'C'
    board[row][col] = 'C'
    // 上下左右递归相邻的 'O'
    const dirs = [[-1,0], [1,0], [0,-1], [0,1]];
    for (const [dr, dc] of dirs) {
      const r = row + dr;
      const c = col + dc;
      if (board[r]?.[c] === 'O') dfs(r, c);
    }
  };

  for (let i = 0; i < board.length; i++) {
    // 找到左右边界上的 'O' 进行递归标记
    if (board[i][0] === 'O') dfs(i, 0)
    if (board[i][board[0].length - 1] === 'O') dfs(i, board[0].length - 1)
  }

  for (let i = 0; i < board[0].length; i++) {
    // 找到上下边界上的 'O' 进行递归标记
    if (board[0][i] === 'O') dfs(0, i)
    if (board[board.length - 1][i] === 'O') dfs(board.length - 1, i)
  }
  // 遍历整个 board, 'O' --> 'X', 'C' --> 'O'
  for (let i = 0; i < board.length; i++) {
    for (let j = 0; j < board[0].length; j++) {
      if (board[i][j] === 'O') board[i][j] = 'X'
      if (board[i][j] === 'C') board[i][j] = 'O'
    }
  }
}

题目来源:力扣(LeetCode)

相关推荐
ZhengEnCi6 小时前
Agent 架构怎么选:从单 Agent 到多 Agent 编排的选型决策指南
算法·架构
秋天的怀念_David7 小时前
第二十二夜 · 数字迷雾
java·程序人生·算法
Pniubi7 小时前
力扣283移动零(双指针法)
算法·leetcode·职场和发展
hhb_6188 小时前
大模型落地三重优化实战
人工智能·算法·机器学习
云和数据.ChenGuang8 小时前
光哥说Python RAG 系统需要哪些评估指标:从检索到生成的全链路评测指南
网络·人工智能·python·算法·langchain
apple-mapping8 小时前
网络RTK定位学习总结
学习·网络rtk
2601_970703839 小时前
工业除湿机租赁:把一份租金合同拆开看
大数据·数据结构·算法·数据库架构·推荐算法
心中有你02149 小时前
Java实现Dijkstra最短路径算法(邻接表 + 优先队列)
java·数据库·算法
楚山之石9 小时前
【Lancet Neurology 】多发性硬化认知障碍的 SDMT 筛查、灰质萎缩标志与认知康复循证路径
图像处理·人工智能·学习·mri
ZhengEnCi10 小时前
同样的模型,为什么本地和云 API 差别那么大:量化精度、聊天模板与采样参数的三大元凶
人工智能·算法·llm