携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第32天,点击查看活动详情
题目描述
给你一个 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'
解题思路
给定一个二维数组board,数组中元素只包含'O','X'。将二位数数组中所有不和边界'O'直接或间接关联的'O'元素替换成'X'。
根据题意,这道题的重点就是要找出所有与边界'0'直接或间接关联的点;
比如点(1,0)为'0',则与它直接关联的点有(2,0),(1,1),(0,0)。即对原坐标进行四个方向的加减(1,0),(-1,0),(0,1),(0,-1);
即上下左右四个方向,然后这几个点又有直接关联的上下左右四个点,依次类推,直到这些关联的点元素不是'O';
所以解这道题有深度优先和广度优先两种选择;
深度优先
遍历上、下、左、右边界的元素,每一次找一个方向上所有的直接或间接与'O'关联的元素,将它们替换成其它元素,比如'B';
遍历完成之后将原数组进行遍历,找到不是'B'且是'O'的元素,将它们设置成'X',然后再将元素值为'B'的替换成'O';
广度优先
第一层遍历获取上、下、左、右边界上所有的'O'元素,将它们设置成其它的元素,比如'B',将它放入队列queue中;
遍历queue,截止条件为queue为空,每一次循环从queue中弹出栈顶元素,然后对原坐标进行四个方向的加减(1,0),(-1,0),(0,1),(0,-1);
获取与当前元素直接关联的节点,判断如果计算出来的位置的元素为'O',则将这个节点的位置放入queue中,并且将该元素修改为'B';
queue队列内容为空时,即找完二维数组中所有直接或间接与边界'O'关联的元素,此时再遍历二维数组,将元素值不是'B'且元素值为'O'的元素替换成'X',然后再将元素值为'B'的替换成'O';
代码实现
public void solve(char[][] board) {
n = board.length;
m = board[0].length;
// 深度优先
// 第一层左右边界
for (int i=0; i < n;i ++) {
// 第一列
dfs(board,i,0);
// 末尾列
dfs(board,i,m-1);
}
// 上下边界
for (int i=0; i < m;i ++) {
// 第一列
dfs(board,0,i);
// 末尾列
dfs(board,n-1,i);
}
// System.out.print("[");
for (int i=0;i<n;i++) {
for (int j=0;j<m;j++) {
if (board[i][j] != 'B') {
board[i][j] = 'X';
} else {
board[i][j] = 'O';
}
}
// System.out.print(Arrays.toString(board[i]));
}
// System.out.print("]");
}
private void dfs(char[][] board, int x, int y) {
if (x < 0 || x >= n || y < 0 || y >= m || board[x][y] != 'O') {
// 截止条件,四个方向的值超出矩阵范围或者当前查找元素不是目标替换元素 则直接返回
return;
}
// 修改当前查找元素为'B'
board[x][y] = 'B';
// 递归查找四个方向的元素
for (int[] ints : direction) {
dfs(board,x+ints[0],y+ints[1]);
}
}