被围绕的区域[bfs & dfs基本练习]

183 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第33天,被围绕的区域[bfs & dfs基本练习] - 掘金 (juejin.cn)

前言

dfs深度优先遍历,常与树的前序遍历和图的节点遍历紧密相关;bfs宽度优先遍历,常与树的层序遍历和图的节点遍历紧密相关。

一、被围绕的区域

image.png

二、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 被围绕的区域