LeetCode琅琊榜第十四层-被围绕的区域

LeetCode.130被围绕的区域

难度:中等

博主空间往期力扣

题目链接  


目录

作者原始思路 

深度优先之失败版

思想与代码简述

问题

反省

官方解法-DFS深度优先搜索算法

题目分析

好处(重要)

算法思想

代码实现

代码分析

结论


作者原始思路 

深度优先之失败版

class Solution {
    public boolean isChange;
    public void solve(char[][] board) {
        var isVisited = new boolean[board.length][board[0].length];
        if (board.length < 3 || board[0].length < 3) {
            return;
        }
        for (int i = 0; i < board.length - 1; i++) {
            for (int j = 0; j < board[i].length - 1; j++) {
                if (board[i][j] == 'O' && !isVisited[i][j]) {
                    isChange = true;
                    dfs(board,isVisited,i,j);
                }
            }
        }
    }
        private  void dfs(char[][] board, boolean[][] isVisited, int curR, int curC) {
        isVisited[curR][curC] = true;
        int[] des = get(curR,curC,isVisited,board);
        if (des != null) {
            if (des[0] == 0 || des[0] == board.length - 1 || des[1] == 0 || des[1] == board[0].length - 1) {
                isChange = false;
            }
            dfs(board,isVisited,des[0],des[1]);
        }
        if (isChange) {
            board[curR][curC] = 'X';
        }
    }

    private  int[] get(int curR, int curC, boolean[][] isVisited,char[][] board) {
        if (curC >= board[0].length - 1 || curR >= board.length - 1) {
            return null;
        }
        if (!isVisited[curR][curC+1] && board[curR][curC+1] == 'O') {
            return new int[] {curR,curC+1};
        }else if (!isVisited[curR+1][curC] && board[curR+1][curC] == 'O') {
            return new int[] {curR+1,curC};
        }else if (!isVisited[curR-1][curC] && board[curR+-1][curC] == 'O') {
            return new int[] {curR-1,curC};
        }else if (!isVisited[curR][curC-1] && board[curR][curC-1] == 'O') {
            return new int[] {curR,curC-1};
        }
        else {
            return null;
        }
    }
}

思想与代码简述

  • 1. 首先,我们先看数组是否少于三列或三行,如果少于三列或三行就直接返回(因为两列以内一定不可能有O被围绕)
  • 2.通过外部循环,我们找到第一个是O的元素的位置,然后找到该位置上所有与他相邻的O的位置,即DFS
  • 3.注意的是:为了避免这层循环重复访问元素,我们可以建立一个状态数组判断其是否被访问过,如果没有被访问过再进行
  • 4.isChange每次都初始化为true,表示可以改变
  • 5.进入dfs,先让当前元素设置成已访问,然后得到下一个位置,即get方法,先判断边界问题,然后直接返回下一个位置,如果没有则返回空
    • 注意:这里用数组来存储位置
  • 6.如果得到了位置,先判断该位置是否为空,如果不为空再判断是否在边界,如果在边界则设置为isChange = false表示不可改变
  • 7.继续向下dfs,最后根据isChange改变即可

问题

  • 该方法理论上是可以的,但是,经过了我的努力,终于看出了问题,
    • 1.即在get方法中的边界问题没有处理好,导致找到一半找不下去了
    • 2.代码超级冗余,我自己都看不下去了,太难受了
    • 3.上述的两个问题导致案例只通过了一半,而且写法超丑

反省

  • 对于DFS深度优先算法,我们应该学会不用这么多判断语句去往下走,我们应该灵活的利用DFS深入

官方解法-DFS深度优先搜索算法

题目分析

  • 题目中要求我们修改被X围绕的O的元素,将这些元素都改为X,我们发现,只要这些O直接或间接的接触到边界上的O,这些O将无法改变,即有边界O的参与,所有涉及的O都无法改变
  • 所以,我们不妨从边界开始递归搜索,找到与边界O所有相邻的O

好处(重要)

  • 如果我们从边界开始搜索,那么我们递归找到的肯定都是不能够修改的O,不需要判断,我们就省去了找可以修改的O,减少递归次数,算法效率提高
  • 如果我们从里面开始搜索,我们不仅找得到可以改的,也可以找得到不可以改的,这就是博主一开始的思想,要判断是否可以改算法效率极差

算法思想

1.利用DFS深度优先搜索开始搜索边界的O

代码实现

class Solution {
    public int row;
    public int col;
    public void solve(char[][] board) {
        row = board.length;
        col = board[0].length;
        for (int i = 0; i < col; i++) {
            dfs(board,0,i);
            dfs(board,row - 1,i);
        }
        for (int i = 0; i < row; i++) {
            dfs(board,i,0);
            dfs(board,i,col-1);
        }
        for (int i = 0; i < row ; i++) {
            for (int j = 0; j < col; j++) {
                if (board[i][j] == ' ') {
                    board[i][j] = 'O';
                }else if (board[i][j] == 'O') {
                    board[i][j] = 'X';
                }
            }
        }
    }
        private void dfs(char[][] board, int r, int c) {
        if (r > row - 1 || r < 0 || c > col - 1 || c < 0 || board[r][c] != 'O')  {
            return;
        }
        board[r][c] = ' ';
        dfs(board,r+1,c);
        dfs(board,r,c+1);
        dfs(board,r-1,c);
        dfs(board,r,c-1);
    }
    
}

代码分析

  • 1.建立两个属性,分别是row与col,用于记录对应的行与列,减少递归传入的参数,美化代码
    • 即:如果以后发现,在DFS中,每次都要传递的参数都一样,我们可以考虑将其设置为属性
  • 2.前面两个for循环,对应着从边界开始去深度优先
  • 3.深度优先dfs
    • 3.1参数
      • board即题目所给的画板
      • r为当前的行的下标
      • c为当前的列的下标
    • 3.2先判断边界情况,r的边界无非是0与row - 1,c的边界无非是0和col-1,如果超过这个边界说明不能走了,直接弹栈
    • 3.3注意这里还有一个!='O'的条件,如果不等于'O',说明与边界O相邻的O在当前位置上没有了,可以直接弹栈
    • 3.4将该位置设置为' '
    • 3.5向上下左右去走即可
  • 4.最后一个for循环,再遍历一次board
    • 4.1如果发现该位置为' ',说明这肯定是DFS深度优先搜索与边界O相邻的O,这些O都不可以改变成X,所以直接赋值O即可
    • 4.2如果发现该位置为'O',说明这肯定没有被DFS深度优先搜索到,说明不是边界O相邻的O,即被包围的O,赋值X,表示更改

结论

        深度优先不仅可以创建树,还可以去弄各种各样的东西,所以,积硅步,至千里,最后我来总结必须要掌握的几点

        1.为什么从边界遍历开始,有什么优势

                2.dfs算法的实现

猜你喜欢

转载自blog.csdn.net/JOElib/article/details/124693219