携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第33天,被围绕的区域[bfs & dfs基本练习] - 掘金 (juejin.cn)
前言
dfs深度优先遍历,常与树的前序遍历和图的节点遍历紧密相关;bfs宽度优先遍历,常与树的层序遍历和图的节点遍历紧密相关。
一、被围绕的区域
二、bfs & dfs
1、dfs深度优先
// 被围绕的区域
public class Solve {
/*
从四个边走,能走到的地方都不能被包围,走不到的地方都会被包围。
bfs || dfs都可。
*/
// review:养成先写思路,再写主键,最后写代码的习惯,不急,一步一步锻炼自己。
static int[][] bounds;
// 把边缘走不到的'O'都用'#'标注。
public void solve(char[][] board) {
// 方便对4边的位置开始dfs
// bug1:开始边界定错了,以为是NxN,现实是MxN
bounds = new int[][]{{0, 0}, {board.length - 1, board[0].length - 1}};
// 以4边的节点'O'开始dfs
for (int[] bound : bounds) {
for (int j = 0; j < board[0].length; j++) dfs(board, bound[0], j);
for (int j = 0; j < board.length; j++) dfs(board, j, bound[1]);
}
// 把标注的'#'还原成'O',把未标注的'O'换成‘X’
for (int i = 0; i < board.length; i++)
for (int j = 0; j < board[0].length; j++)
board[i][j] = board[i][j] == 'O' ? 'X' : board[i][j] == '#' ? 'O' : 'X';
}
// 方便上下左右dfs
static int[][] gaps = new int[][]{{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
public void dfs(char[][] board, int i, int j) {
// 越界 || 该位置已经访问过 || 该位置走不通
if (i == -1 || -1 == j
|| j == board[0].length || board.length == i
|| board[i][j] == '#'
|| board[i][j] == 'X') return;
// 访问了当前位置,其位置为‘O’,是一个不被包围的'O',进行‘#’号标注。
board[i][j] = '#';
// 往上下左右走。
for (int[] gap : gaps) dfs(board, i + gap[0], j + gap[1]);
}
}
2、bfs宽度优先
class Solve2 {
/*
从四个边走,能走到的地方都不能被包围,走不到的地方都会被包围。
bfs || dfs都可。
*/
// review:养成先写思路,再写主键,最后写代码的习惯,不急,一步一步锻炼自己。
static int[][] bounds;
// 把边缘走不到的'O'都用'#'标注。
public void solve(char[][] board) {
// 方便对4边的位置开始bfs
// bug1:开始边界定错了,以为是NxN,现实是MxN
bounds = new int[][]{{0, 0}, {board.length - 1, board[0].length - 1}};
// 以4边的节点'O'开始bfs
for (int[] bound : bounds) {
for (int j = 0; j < board[0].length; j++) bfs(board, bound[0], j);
for (int j = 0; j < board.length; j++) bfs(board, j, bound[1]);
}
// 把标注的'#'还原成'O',把未标注的'O'换成‘X’
for (int i = 0; i < board.length; i++)
for (int j = 0; j < board[0].length; j++)
board[i][j] = board[i][j] == 'O' ? 'X' : board[i][j] == '#' ? 'O' : 'X';
}
// 方便上下左右dfs
static int[][] gaps = new int[][]{{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
// bfs标注可达节点
public void bfs(char[][] board, int i, int j) {
Queue<int[]> que = new LinkedList<>();
que.add(new int[]{i,j});
while (!que.isEmpty()){
int[] node = que.poll();
// 自身是可达节点。
if(board[node[0]][node[1]] != 'O') continue;
board[node[0]][node[1]] = '#';
// 可达节点加入队列,进行bfs遍历。
for (int[] gap : gaps) {
int ni = gap[0] + node[0], nj = gap[1] + node[1];
if(ni != -1 && nj != -1
&& ni != board.length && board[0].length != nj
&& board[ni][nj] == 'O') que.add(new int[]{ni,nj});
}
}
}
}
总结
1)BFS & DFS的基本练习,一个利用栈思想递归,一个利用队列将多层排在一个队列中。
2)养成先写思路,再写主键,最后写代码的习惯,不急,一步一步锻炼自己。
参考文献
[1] LeetCode 被围绕的区域