【LeetCode】130. 被围绕的区域

题目链接

130. 被围绕的区域

题目描述

给定一个二维的矩阵,包含 'X' 和 'O'(字母 O)。

找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O' 用 'X' 填充。

示例:
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'。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。

解题思路

(1) DFS思路一

利用dfs递归将board地图中所有的“O”的找出,并用两个数组记录他们的座标,其次从两个座标数组中判断是否包含了边界点的“O”,如果有则清空数据,如果没有则直接把两个座标数组中对应的点改为“X”即可。

(2) DFS思路二

可以直接从边界点"O"出发,利用DFS查找所有与边界点“O”相邻的“O”,这些点不能改变,其余“O”直接变为“X”即可。

AC代码

(1)DFS实现方式一

class Solution {
    // lsX与lxY两个数组用于"O"的横纵座标
    ArrayList<Integer> lsX = new ArrayList<>();
    ArrayList<Integer> lsY = new ArrayList<>();
    //dir方向数组(上下左右)
    int dir[][] = {{0,1},{1,0},{-1,0},{0,-1}};
    void dfs(int x,int y,char[][] map,int[][] view){
        //情况一:下标越界
        if(x<0 || x>=map.length || y<0 || y>=map[0].length) return;
        //情况二:我们寻找的是”O”点,不是“X”点。
        if(map[x][y] == 'X') return;
        //情况三:该座标点已经遍历过
        if(view[x][y] == 1) return;
        if(map[x][y] == 'O'){
           //如果座标点对应的字符是我们需要的“O”,则记录其横纵座标。并标记此点已经遍历,防止重复遍历。
            view[x][y] = 1;
            lsX.add(x);
            lsY.add(y);
        }
        //DFS框架
        for(int i = 0; i < 4; i++){
            int xx = x + dir[i][0];
            int yy = y + dir[i][1];
            dfs(xx,yy,map,view);
        }
    }

    //cal函数用于判断lsX以及lsY数组中是否包含处于边界的“O”
    int cal(ArrayList<Integer> lsX,ArrayList<Integer> lsY,int a,int b){
        if(lsX.contains(new Integer(0)) || lsX.contains(new Integer(a))
         || lsY.contains(new Integer(0)) || lsY.contains(new Integer(b))){
             return 1;
         }
        else return 0;

    }

    public void solve(char[][] board) {
        if(board.length == 0 ) return;
        //view数组用于记录点x,y是否已经遍历过,防止重复遍历。
        int[][] view = new int[board.length][board[0].length];
        for(int i = 0; i < board.length; i++){
            for(int j = 0; j < board[0].length; j++)
            {
                if(board[i][j] == 'O'){
                    dfs(i,j,board,view);
                    //cal函数用于判断lsX以及lsY数组中是否包含处于边界的“O”,如果有,这些点按照题目要求
                    //不能够更改,所以清空数组
                    if(cal(lsX,lsY,board.length-1,board[0].length-1) == 1){
                        lsY.clear();
                        lsX.clear();
                    }
                    else{
                        for(int z = 0; z < lsX.size(); z++){
                            board[lsX.get(z).intValue()][lsY.get(z).intValue()] = 'X';
                        }
                    }
                }
            }
        }
    }
}

(2)DFS实现方式二

class Solution {
    public void solve(char[][] board) {
        if (board == null || board.length == 0) return;
        int m = board.length;
        int n = board[0].length;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                // 从边缘o开始搜索
                boolean isEdge = i == 0 || j == 0 || i == m - 1 || j == n - 1;
                if (isEdge && board[i][j] == 'O') {
                    dfs(board, i, j);
                }
            }
        }

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (board[i][j] == 'O') {
                    board[i][j] = 'X';
                }
                if (board[i][j] == '#') {
                    board[i][j] = 'O';
                }
            }
        }
    }

    public void dfs(char[][] board, int i, int j) {
        if (i < 0 || j < 0 || i >= board.length  || j >= board[0].length || board[i][j] == 'X' || board[i][j] == '#') {
            // board[i][j] == '#' 说明已经搜索过了. 
            return;
        }
        board[i][j] = '#';
        dfs(board, i - 1, j); // 上
        dfs(board, i + 1, j); // 下
        dfs(board, i, j - 1); // 左
        dfs(board, i, j + 1); // 右
    }
}

链接:https://leetcode-cn.com/problems/surrounded-regions/solution/bfsdi-gui-dfsfei-di-gui-dfsbing-cha-ji-by-ac_pipe/

(3)DFS非递归实现

非递归的方式,我们需要记录每一次遍历过的位置,我们用 stack 来记录,因为它先进后出的特点。而位置我们定义一个内部类 Pos 来标记横座标和纵座标。注意的是,在写非递归的时候,我们每次查看 stack 顶,但是并不出 stack,直到这个位置上下左右都搜索不到的时候出栈。(代码中continue语句是关键

class Solution {
    public class Pos{
        int i;
        int j;
        Pos(int i, int j) {
            this.i = i;
            this.j = j;
        }
    }
    public void solve(char[][] board) {
        if (board == null || board.length == 0) return;
        int m = board.length;
        int n = board[0].length;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                // 从边缘第一个是o的开始搜索
                boolean isEdge = i == 0 || j == 0 || i == m - 1 || j == n - 1;
                if (isEdge && board[i][j] == 'O') {
                    dfs(board, i, j);
                }
            }
        }

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (board[i][j] == 'O') {
                    board[i][j] = 'X';
                }
                if (board[i][j] == '#') {
                    board[i][j] = 'O';
                }
            }
        }
    }

    public void dfs(char[][] board, int i, int j) {
        Stack<Pos> stack = new Stack<>();
        stack.push(new Pos(i, j));
        board[i][j] = '#';
        while (!stack.isEmpty()) {
            // 取出当前stack 顶, 不弹出.
            Pos current = stack.peek();
            // 上
            if (current.i - 1 >= 0 
                && board[current.i - 1][current.j] == 'O') {
                stack.push(new Pos(current.i - 1, current.j));
                board[current.i - 1][current.j] = '#';
              	continue;//continue语句是关键
            }
            // 下
            if (current.i + 1 <= board.length - 1 
                && board[current.i + 1][current.j] == 'O') {
                stack.push(new Pos(current.i + 1, current.j));
                board[current.i + 1][current.j] = '#';      
                continue;
            }
            // 左
            if (current.j - 1 >= 0 
                && board[current.i][current.j - 1] == 'O') {
                stack.push(new Pos(current.i, current.j - 1));
                board[current.i][current.j - 1] = '#';
                continue;
            }
            // 右
            if (current.j + 1 <= board[0].length - 1 
                && board[current.i][current.j + 1] == 'O') {
                stack.push(new Pos(current.i, current.j + 1));
                board[current.i][current.j + 1] = '#';
                continue;
            }
            // 如果上下左右都搜索不到,本次搜索结束,弹出stack
            stack.pop();
        }
    }
}

作者:Ac_pipe
链接:https://leetcode-cn.com/problems/surrounded-regions/solution/bfsdi-gui-dfsfei-di-gui-dfsbing-cha-ji-by-ac_pipe/

(4)BFS实现

dfs 非递归的时候我们用 stack 来记录状态,而 bfs 非递归,我们则用队列来记录状态。和 dfs 不同的是,dfs 中搜索上下左右,只要搜索到一个满足条件,我们就顺着该方向继续搜索,所以你可以看到 dfs 代码中,只要满足条件,就入 Stack,然后 continue 本次搜索,进行下一次搜索,直到搜索到没有满足条件的时候出 stack。而 dfs 中,我们要把上下左右满足条件的都入队,所以搜索的时候就不能 continue。大家可以对比下两者的代码,体会 bfs 和 dfs 的差异。

class Solution {
    public class Pos{
        int i;
        int j;
        Pos(int i, int j) {
            this.i = i;
            this.j = j;
        }
    }
    public void solve(char[][] board) {
        if (board == null || board.length == 0) return;
        int m = board.length;
        int n = board[0].length;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                // 从边缘第一个是o的开始搜索
                boolean isEdge = i == 0 || j == 0 || i == m - 1 || j == n - 1;
                if (isEdge && board[i][j] == 'O') {
                    bfs(board, i, j);
                }
            }
        }

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (board[i][j] == 'O') {
                    board[i][j] = 'X';
                }
                if (board[i][j] == '#') {
                    board[i][j] = 'O';
                }
            }
        }
    }

    public void bfs(char[][] board, int i, int j) {
        Queue<Pos> queue = new LinkedList<>();
        queue.add(new Pos(i, j));
        board[i][j] = '#';
        while (!queue.isEmpty()) {
            Pos current = queue.poll();
            // 上
            if (current.i - 1 >= 0 
                && board[current.i - 1][current.j] == 'O') {
                queue.add(new Pos(current.i - 1, current.j));
                board[current.i - 1][current.j] = '#';
              	// 没有continue.
            }
            // 下
            if (current.i + 1 <= board.length - 1 
                && board[current.i + 1][current.j] == 'O') {
                queue.add(new Pos(current.i + 1, current.j));
                board[current.i + 1][current.j] = '#';      
            }
            // 左
            if (current.j - 1 >= 0 
                && board[current.i][current.j - 1] == 'O') {
                queue.add(new Pos(current.i, current.j - 1));
                board[current.i][current.j - 1] = '#';
            }
            // 右
            if (current.j + 1 <= board[0].length - 1 
                && board[current.i][current.j + 1] == 'O') {
                queue.add(new Pos(current.i, current.j + 1));
                board[current.i][current.j + 1] = '#';
            }
        }
    }
}
作者:Ac_pipe
链接:https://leetcode-cn.com/problems/surrounded-regions/solution/bfsdi-gui-dfsfei-di-gui-dfsbing-cha-ji-by-ac_pipe/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章