• 飞地的数量


    题目描述

    给你一个大小为 m x n 的二进制矩阵 grid ,其中 0 表示一个海洋单元格、1 表示一个陆地单元格。

    一次 移动 是指从一个陆地单元格走到另一个相邻(上、下、左、右)的陆地单元格或跨过 grid 的边界。

    返回网格中 无法 在任意次数的移动中离开网格边界的陆地单元格的数量。

    在这里插入图片描述

    思路

    首先我们要处理边界问题,因为题中告诉我们,边界的陆地不在计算范围内,所以我们第一步要把四个边界的陆地做处理,也就是把陆地变海洋。代码如下:

    // 处理四个边界
    for(int i = 0;i < m;i++){
        // 左
        if(grid[i][0] == 1) dfs(grid, i, 0, m, n);
        // 右
        if(grid[i][n - 1] == 1) dfs(grid, i, n - 1, m, n);
    }
    for(int i = 0;i < n;i++){
        // 上
        if(grid[0][i] == 1) dfs(grid, 0, i, m, n);
        //下
        if(grid[m - 1][i] == 1) dfs(grid, m - 1, i, m, n);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    接下来的代码就是上次我们讲的岛屿的数量代码,稍微变动即可。

    回溯代码如下:

    public void dfs(int[][] grid, int i, int j, int m, int n){
        if(i >=m || i < 0 || j >= n || j < 0 || grid[i][j] == 0){
            return;
        }
        grid[i][j] = 0;
        count++;
        dfs(grid, i + 1, j, m, n);
        dfs(grid, i - 1, j, m, n);
        dfs(grid, i, j + 1, m, n);
        dfs(grid, i, j - 1, m, n);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    整体代码如下:

    public class NumEnclaves {
    
        int count = 0;
    
        /**
         * 解决思路和Solve一样,都是从四个边开始出发,将与边界相连的1都置为0,之后,再重新计算1的数量即可
         * @param grid
         * @return
         */
        public int numEnclavesWithDfs(int[][] grid) {
            int m = grid.length, n = grid[0].length;
            for(int i = 0;i < m;i++){
                if(grid[i][0] == 1) dfs(grid, i, 0, m, n);
                if(grid[i][n - 1] == 1) dfs(grid, i, n - 1, m, n);
            }
            for(int i = 0;i < n;i++){
                if(grid[0][i] == 1) dfs(grid, 0, i, m, n);
                if(grid[m - 1][i] == 1) dfs(grid, m - 1, i, m, n);
            }
            count = 0;
            for(int i = 0;i < m;i++){
                for(int j = 0;j < n;j++){
                    if(grid[i][j] == 1){
                        dfs(grid, i, j, m, n);
                    }
                }
            }
            return count;
        }
    
        public void dfs(int[][] grid, int i, int j, int m, int n){
    
            if(i < 0 || i >= m || j < 0 || j >= n || grid[i][j] == 0) return;
            grid[i][j] = 0;
            count++;
            dfs(grid, i, j + 1, m, n);
            dfs(grid, i, j - 1, m, n);
            dfs(grid, i - 1, j, m, n);
            dfs(grid, i + 1, j, m, n);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    上面的代码非常耗时,主要是递归会遍历重复的,我们加上标记位置,只要我们遍历过该位置,就把该位置进行标记,下次遍历时,只要该点遍历过,直接跳过即可。代码如下:

    public class NumEnclaves {
    	boolean[][] visited;
    	int count = 0;
        public int numEnclaves(int[][] grid) {
            int m = grid.length, n = grid[0].length;
            visited = new boolean[m][n];
            for(int i = 0;i < m;i++){
                if(grid[i][0] == 1) dfsWithVisited(grid, i, 0, m, n);
                if(grid[i][n - 1] == 1) dfsWithVisited(grid, i, n - 1, m, n);
                
            }
            for(int i = 0;i < n;i++){
                if(grid[0][i] == 1) dfsWithVisited(grid, 0, i, m, n);
                if(grid[m - 1][i] == 1) dfsWithVisited(grid, m - 1, i, m, n);
            }
            for(int i = 0;i < m;i++){
                for(int j = 0;j < n;j++){
                    if(grid[i][j] == 1 && !visited[i][j]){
                        count++;
                    }
                }
            }
            return count;
        }
    
        public void dfsWithVisited(int[][] grid, int i, int j, int m, int n){
            
            if(i < 0 || i >= m || j < 0 || j >= n || grid[i][j] == 0) return;
            grid[i][j] = 0;
            visited[i][j] = true;
            dfsWithVisited(grid, i, j + 1, m, n);
            dfsWithVisited(grid, i, j - 1, m, n);
            dfsWithVisited(grid, i - 1, j, m, n);
            dfsWithVisited(grid, i + 1, j, m, n);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
  • 相关阅读:
    小班中班,随机10以内加法练习题,A4纸可直接打印
    论文笔记:多标签学习——LIFT算法
    《JAVA筑基100例》导读
    后缀自动机(SAM)+广义后缀自动机(GSA)
    【笔试真题记录】2023华为9.20机试第二题(DFS和BFS)
    可防离职员工冒用身份,合合信息名片全能王与钉钉用数字名片打造安全“围栏”
    相似基因序列问题 ——查找
    金仓数据库KMonitor使用指南--2. 监控指标
    Unity 2D 游戏学习笔记(3)
    KT148A4语音芯片芯片设备批量升级_一拖八的工具_V1
  • 原文地址:https://blog.csdn.net/qq_41591215/article/details/133722792