• 【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/
    
    
  • 相关阅读:
    。。。剑指Offer之——用两个栈实现队列。。。
    。。。剑指Offer之——从尾到头打印链表。。。
    。。。剑指Offer之——替换空格。。。
    。。。剑指Offer之——二维数组中的查找。。。
    。。。归并排序。。。
    。。。快速排序。。。
    。。。冒泡排序。。。
    。。。选择排序。。。
    。。。Shell排序。。。
    Activiti学习笔记2 — HelloWorld
  • 原文地址:https://www.cnblogs.com/XDU-Lakers/p/13488889.html
Copyright © 2020-2023  润新知