LeetCode130:被围绕的区域(图的简化版之网格结构上的DFS)

题目

在这里插入图片描述
注意:
1 <= m, n <= 200
board[i][j] 为 ‘X’ 或 ‘O’

思路

根据一般网格结构上的DFS,或者说岛屿问题,第一反应很容易想到找出所有的‘O’然后开始DFS遍历,改为‘X’。

但是这里有个联通的问题,如果这个‘O’是边界上的‘O’或者与边界上的‘O’联通,那么它实际上不应该被改为‘X’。

为此我们应该先预处理,从边界上的‘O’出发进行DFS遍历,找出所有与其相连的‘O’,这个过程中为了保证DFS不陷入死循环,我们要将遍历过的‘O’改掉,但是不能改为‘X’,因为最后我们是要把这些‘O’再复原回去的,如果我们改为了‘X’,之后就无法找出具体哪些节点要复原了,所以这里用另外的字母‘N’代替。

预处理后还剩下的‘O’则是与边界的‘O’不连通的点了,我们正常DFS遍历并改为‘X’。

最后则是将所有的‘N’再改回‘O’。

代码

初版代码

class Solution {
   
    public void solve(char[][] board) {
   
        int m = board.length;
        int n = board[0].length;
        //1.预处理边界的O,让其等于N,且从其dfs遍历的点都变为N
        for(int r = 0;r<m;r++){
   
            if(board[r][0]=='O') {
   
                dfs(board,r,0,'N');
            }
            if(board[r][n-1]=='O') {
   
                dfs(board,r,n-1,'N');
            }
        }
        for(int c=0;c<n;c++){
   
            if(board[0][c]=='O') {
   
                dfs(board,0,c,'N');
            }
            if(board[m-1][c]=='O') {
   
                dfs(board,m-1,c,'N');
            }
        }
        //2.遍历剩下所有的O,从其开始出发dfs遍历
        for(int r=0;r<m;r++){
   
            for(int c=0;c<n;c++){
   
                if(board[r][c]=='O')
                dfs(board,r,c,'X');
            }
        }
        //3.将所有的N换回O。
        for(int r=0;r<m;r++){
   
            for(int c=0;c<n;c++){
   
                if(board[r][c]=='N')
                board[r][c]='O';
            }
        }
    }
    public void dfs(char[][] board, int r,int c,char type){
   //为了让边界的O的dfs和不与边界O联通的O的dfs都用同一个函数,这里多加了一个参数type,如果传入的是N,那么说明是前者的dfs,最后点要改为N。如果传入的是X,说明是后者的dfs。最后点要改为X。
        //判断边界情况
        if(!ifCouldVis(board,r,c)) return;
        board[r][c]=type;
        dfs(board,r+1,c,type);
        dfs(board,r,c+1,type);
        dfs(board,r-1,c,type);
        dfs(board,r,c-1,type);
    }

    public boolean ifCouldVis(char[][] board,int r,int c){
   
        return r>=0 && c>=0 && r<board.length && c<board[0].length && board[r][c]=='O';
    }
}

4ms,击败17.92%使用 Java 的用户。说明还需要优化。

第二版代码

根据思路发现第一版代码存在三步。

  1. 找出所有边界上的O,用DFS找出与其联通的O点,将其改为N
  2. 找出剩下的所有O,用DFS找出与其联通的O点,将其改为X
  3. 还原所有的N为O

我们发现第二步的DFS是多余的,因为我们只需要把剩下所有的O改为X即可,不需要找出与其联通的O点。那么第二步的代码应该由

//2.遍历剩下所有的O,从其开始出发dfs遍历
        for(int r=0;r<m;r++){
   
            for(int c=0;c<n;c++){
   
                if(board[r][c]=='O')
                dfs(board,r,c,'X');
            }
        }

变更为

 //2.遍历剩下所有的O,从其开始出发dfs遍历
        for(int r=0;r<m;r++){
   
            for(int c=0;c<n;c++){
   
                if(board[r][c]=='O')
                board[r][c]='X';
            }
        }

此时再测效率,1ms,击败99.81%使用 Java 的用户

但是既然第二步的dfs没有了,那么传入的type参数也没用了。我们也不需要第二步和第三步分别在两个循环中,直接合并为一个循环即可,因为两层for循环是从上到下,从左到右依次循环的,所以第三步改回去的‘O’不会影响到第二步的‘O’的判断·。最终代码如下:

class Solution {
   
    public void solve(char[][] board) {
   
        int m = board.length;
        int n = board[0].length;
        //1.预处理边界的O,让其等于N,且从其dfs遍历的点都变为N
        for(int r = 0;r<m;r++){
   
            if(board[r][0]=='O') {
   
                dfs(board,r,0);
            }
            if(board[r][n-1]=='O') {
   
                dfs(board,r,n-1);
            }
        }
        for(int c=0;c<n;c++){
   
            if(board[0][c]=='O') {
   
                dfs(board,0,c);
            }
            if(board[m-1][c]=='O') {
   
                dfs(board,m-1,c);
            }
        }
        //2.遍历整个网格,因为两层for循环是从上到下,从左到右依次循环的,所以由‘N’改回去的‘O’不会影响到原来不连通的‘O’的判断·
        for(int r=0;r<m;r++){
   
            for(int c=0;c<n;c++){
   
                if(board[r][c]=='O') board[r][c]='X';
                if(board[r][c]=='N') board[r][c]='O';
            }
        }
    }
    public void dfs(char[][] board, int r,int c){
   
        //判断边界情况
        if(!ifCouldVis(board,r,c)) return;
        board[r][c]='N';
        dfs(board,r+1,c);
        dfs(board,r,c+1);
        dfs(board,r-1,c);
        dfs(board,r,c-1);
    }

    public boolean ifCouldVis(char[][] board,int r,int c){
   
        return r>=0 && c>=0 && r<board.length && c<board[0].length && board[r][c]=='O';
    }
}

效率没有变动,依旧是1ms,但是代码简洁了很多。

相关推荐

  1. DFS130.围绕区域

    2024-02-07 21:34:02       39 阅读
  2. 力扣:130. 围绕区域

    2024-02-07 21:34:02       37 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-02-07 21:34:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-02-07 21:34:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-02-07 21:34:02       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-02-07 21:34:02       20 阅读

热门阅读

  1. 进程基础(命令的基石)

    2024-02-07 21:34:02       27 阅读
  2. Android:多线程下载&网络图片

    2024-02-07 21:34:02       32 阅读
  3. 题目 1155: C语言训练-阶乘和数*

    2024-02-07 21:34:02       29 阅读
  4. golang压缩与解压缩文件

    2024-02-07 21:34:02       30 阅读
  5. K8S系列文章之 [基于 Alpine 使用 kubeadm 搭建 k8s]

    2024-02-07 21:34:02       35 阅读
  6. 假期2.6

    2024-02-07 21:34:02       27 阅读
  7. Spring Boot RestTemplate请求证书问题

    2024-02-07 21:34:02       28 阅读
  8. 谈谈开源软件的影响力

    2024-02-07 21:34:02       28 阅读