本文已参与「新人创作礼」活动,一起开启掘金创作之路。
被围绕的区域
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'。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。
示例 2:
输入:board = [["X"]]
输出:[["X"]]
提示:
- m == board.length
- n == board[i].length
- 1 <= m, n <= 200
- board[i][j] 为 'X' 或 'O'
解题思路
直接判断包围 + 覆盖
- 判断是否包围
- 如果包围着将 O覆盖为 X。
这两个功能都能用dfs来实现,所以我直接将代码整合成一个dfs,传入一个bool值来区分两个功能,整体上代码会简洁很多。
有几个小技巧可以注意下:
- 判断某个点是否已经遍历过,我们可以将点转化为数进行判断,比如这里的点 (i,j) ,i<r, j < c,那么以 i * c + j 这个数来表示这个点(将点映射为数值)
- 判重使用集合来判断会比直接使用数组效果好很多
- 使用数组存储方向,然后对数组进行遍历,比分别枚举四个方向要简洁的多。
代码实现
var solve = function(board) {
let dx = [0,1,0,-1];
let dy = [1,0,-1,0];
let r = board.length;
if(r == 0)return;
let c= board[0].length;
for(let i = 0 ; i < r; i++){
for(let j = 0 ; j < c;j++){
if(board[i][j] == "O"){
if( dfs(i,j,false, new Set([ i*c+j ] ) ) ){//判断是否被包围,
dfs(i,j,true, new Set([ i*c+j ] )); // O 如果被X 包围,则覆盖当前区域
}
}
}
}
function dfs(i,j,over, vis){ //over 表示是否将o 覆盖为x , 返回值表示是否被X包围
if(i == 0 || j == 0 || i == r-1 || j ==c-1)return false;
let flag=true;
for(let k = 0 ; k < 4; k++){ //遍历四个方向
let x = i+dx[k], y = j+dy[k];
let cur = x * c + y ;
if(board[ x ][ y] == "O" && !vis.has(cur) ){
flag = flag && dfs(x,y,over, vis.add(cur));
}
}
if(over){
board[i][j]="X";
}
return flag;
}
};