「这是我参与2022首次更文挑战的第 17 天,活动详情查看:2022首次更文挑战」
题目链接
130. 被围绕的区域 - 力扣(LeetCode) (leetcode-cn.com)
题目描述
给你一个 m x n 的矩阵 board ,由若干字符 'X' 和 'O' ,找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O' 用 'X' 填充。
测试用例
示例 1:
输入:board = [["X","X","X","X"],["X","O","O","X"],["X","X","O","X"],["X","O","X","X"]]
输出:[["X","X","X","X"],["X","X","X","X"],["X","X","X","X"],["X","O","X","X"]]
解释:被围绕的区间不会存在于边界上,换句话说,任何边界上的 'O' 都不会被填充为 'X'。 任何不在边界上,或不与边界上的 'O' 相连的 'O' 最终都会被填充为 'X'。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。
条件限制
- m == board.length
- n == board[i].length
- 1 <= m, n <= 200
- board[i][j] 为 'X' 或 'O'
题目分析
在一个 m * n 的矩阵里,每个元素都会被填充为 X 或 O,对于四周边界上的 O 以及与之关联的 O 都需要保留下来,其他的元素需要将值都替换为 X
一个常规的思路,就是完整的遍历这个二维数组,记录下已经遍历过的坐标,当遇到值为 O 时,尝试向四周遍历查找同样为 O 且还未被遍历过的坐标,直到遍历到再也找不到为 O 的坐标,记录最后终止的 O 的坐标是否在四周的边界上:如果在边界上,这些 O 坐标就不需要处理,否则就需要全部修改为 X,当所有的坐标都遍历完成处理好后,返回原数组就行
这里分享第二种解法:尝试遍历四周的坐标,如果找到了坐标为 O 的,再通过深度搜索的方式找到坐标同样为 O 的,将这些坐标都标记为临时的值,如 T。然后矩阵里还未被修改的 O 就是需要我们修改为X。最后我们完整的遍历一次矩阵,调整坐标的值 O -> x, T -> O 即可
代码实现
/**
* @param {character[][]} board
* @return {void} Do not return anything, modify board in-place instead.
*/
// m 行,n 列
var solve = function(board) {
let m = board.length,
n = board[0].length;
// 遍历四周一圈,将关联的 O => T
[0, m - 1].forEach(row => {
for (let j = 0; j < n; j++) {
trave(board, row, j);
}
});
[0, n - 1].forEach(col => {
for (let i = 0; i < m; i++) {
trave(board, i, col);
}
});
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
if (board[i][j] == 'O') board[i][j] = 'X';
if (board[i][j] == 'T') board[i][j] = 'O';
}
}
return board;
function trave(arrs, i, j) {
if (arrs[i][j] != 'O') return;
arrs[i][j] = 'T';
if (i > 0) trave(arrs, i - 1, j);
if (i < m - 1) trave(arrs, i + 1, j);
if (j > 0) trave(arrs, i, j - 1);
if (j < n - 1) trave(arrs, i, j + 1);
}
};
解法1比较常规,且需要我们记录下已经遍历的坐标,并且涉及到递归和回溯操作,比较繁琐且需要额外的空间来记录已经遍历的值
解法2 就有点取巧了,第一个只遍历四周坐标+深度搜索相关坐标再标记区分需要保留的坐标值,第二次才会完整的遍历整个矩阵再统一调整整个矩阵的值,思路简单明了且不需要额外的空间