每天学习一点算法 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)