图论系列(dfs岛屿) 9/26

一、统计封闭岛屿的数目

二维矩阵 grid0 (土地)和 1 (水)组成。岛是由最大的4个方向连通的 0 组成的群,封闭岛是一个 完全 由1包围(左、上、右、下)的岛。

请返回 封闭岛屿 的数目。

复制代码
输入:grid = [[1,1,1,1,1,1,1],
             [1,0,0,0,0,0,1],
             [1,0,1,1,1,0,1],
             [1,0,1,0,1,0,1],
             [1,0,1,1,1,0,1],
             [1,0,0,0,0,0,1],
             [1,1,1,1,1,1,1]]
输出:2
思路:

当gridxy=0的时候,我们开始遍历;对每个节点进行dfs搜索

如果该节点正好是第一行第一列或者最后一行最后一列,那么直接返回false;(因为已经到达边界了,就无法被包围了)

如果该节点正好是1并且没有被访问过,返回true,周围是1,满足被包围的条件。

向四个方向递归调用dfs,只有同时满足true,才能说明是被包围的。

代码:
java 复制代码
class Solution {
    boolean[][] visited;
    public int closedIsland(int[][] grid) {
        int res = 0;
        visited = new boolean[grid.length][grid[0].length];
        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[0].length; j++) {
                if (grid[i][j] == 0 && !visited[i][j]) {
                    if(dfs(grid,i,j))res++;
                }
            }
        }
        return res;
    }

    public boolean dfs(int[][] grid, int x, int y) {
        if (x < 0 || x > grid.length - 1 || y < 0 || y > grid[0].length - 1)
            return false;
        if (grid[x][y] == 1||visited[x][y])
            return true;
        visited[x][y] = true;
        boolean up = dfs(grid, x - 1, y);
        boolean down = dfs(grid, x + 1, y);
        boolean left = dfs(grid, x, y - 1);
        boolean right = dfs(grid, x, y + 1);
        return up && down && left && right;
    }
}

二、被围绕的区域(和飞地的数量类似)

题意:

给定一个m*n的矩阵,由'X'、'O'组成。如果O的四周被X包围,那么O就要改成X;

思路:

1.出现在矩阵边缘的O定不会被包围,首先寻找未被包围的'O',通过dfs边缘的O,寻找连通子块。

java 复制代码
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                if ((i == 0 || i == board.length - 1 || j == 0 || j == board[0].length - 1) && board[i][j] == 'O') {
                    dfs(board, i, j);
                }
            }
        }

2.然后剩下的O就是被包围的,将他们标记成X;最后将连通子块标记成O

java 复制代码
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                if (board[i][j] == 'O')
                    board[i][j] = 'X';
            }
        }
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                if (board[i][j] == 'A')
                    board[i][j] = 'O';
            }
        }
    }
代码:
java 复制代码
class Solution {
    boolean[][] visited;

    public void solve(char[][] board) {
        visited = new boolean[board.length][board[0].length];
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                if ((i == 0 || i == board.length - 1 || j == 0 || j == board[0].length - 1) && board[i][j] == 'O') {
                    dfs(board, i, j);
                }
            }
        }
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                if (board[i][j] == 'O')
                    board[i][j] = 'X';
            }
        }
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                if (board[i][j] == 'A')
                    board[i][j] = 'O';
            }
        }
    }

    public void dfs(char[][] board, int x, int y) {
        if (x < 0 || x > board.length - 1 || y < 0 || y > board[0].length - 1 || board[x][y] != 'O')
            return;
        board[x][y] = 'A';
        dfs(board, x - 1, y);
        dfs(board, x + 1, y);
        dfs(board, x, y - 1);
        dfs(board, x, y + 1);
    }
}

三、统计子岛屿

给定两个岛屿,看岛屿b中的岛屿是不是岛屿a中的子岛屿。

思路1(叠加法):

因为1是陆地,所以将两个岛屿中的1相加起来,如果为2,这就是他们重叠的陆地。

如果值为2的岛屿中含有值为1的陆地,那么他就不是子岛屿;

如果都是2,说明是子岛屿。

1.叠加两个岛屿的陆地

java 复制代码
        for (int i = 0; i < grid2.length; i++) {
            for (int j = 0; j < grid2[0].length; j++) {
                if (grid2[i][j] == 1)
                    grid2[i][j] += grid1[i][j];
            }
        }

2.然后在叠加后中寻找值都为2的岛屿

java 复制代码
    public boolean dfs(int[][] grid, int x, int y) {
        if (x < 0 || x > grid.length - 1 || y < 0 || y > grid[0].length - 1||visited[x][y])
            return true;
        if (grid[x][y] !=2)
            return grid[x][y]==0;
        visited[x][y] = true;
        boolean up = dfs(grid, x - 1, y);
        boolean down = dfs(grid, x + 1, y);
        boolean left = dfs(grid, x, y - 1);
        boolean right = dfs(grid, x, y + 1);
        return up&&down&&left&&right;
    }
代码:
java 复制代码
class Solution {
    boolean[][] visited;

    public int countSubIslands(int[][] grid1, int[][] grid2) {
        visited = new boolean[grid1.length][grid1[0].length];
        for (int i = 0; i < grid2.length; i++) {
            for (int j = 0; j < grid2[0].length; j++) {
                if (grid2[i][j] == 1)
                    grid2[i][j] += grid1[i][j];
            }
        }
        int res = 0;
        for (int i = 0; i < grid2.length; i++) {
            for (int j = 0; j < grid2[0].length; j++) {
                if (grid2[i][j] == 2 && !visited[i][j]) {
                    if(dfs(grid2,i,j))res++;
                }
            }
        }
        return res;
    }

    public boolean dfs(int[][] grid, int x, int y) {
        if (x < 0 || x > grid.length - 1 || y < 0 || y > grid[0].length - 1||visited[x][y])
            return true;
        if (grid[x][y] !=2)
            return grid[x][y]==0;
        visited[x][y] = true;
        boolean up = dfs(grid, x - 1, y);
        boolean down = dfs(grid, x + 1, y);
        boolean left = dfs(grid, x, y - 1);
        boolean right = dfs(grid, x, y + 1);
        return up&&down&&left&&right;
    }
}
思路2(淹没法):

在相同的位置处,如果矩阵2中是陆地,矩阵1中是海洋。那么这一定不是子岛屿,直接将该陆地的连通子块都淹没掉。

淹没完不是子岛屿的岛屿,剩下的就是子岛屿的岛屿。再次寻找即可

代码:
java 复制代码
class Solution {
    boolean[][] visited;

    public int countSubIslands(int[][] grid1, int[][] grid2) {
        visited = new boolean[grid1.length][grid1[0].length];
        for (int i = 0; i < grid2.length; i++) {
            for (int j = 0; j < grid2[0].length; j++) {
                if(grid2[i][j]==1&&grid1[i][j]==0){
                    dfs(grid2,i,j);
                }
            }
        }
        int res = 0;
        for (int i = 0; i < grid2.length; i++) {
            for (int j = 0; j < grid2[0].length; j++) {
                if (grid2[i][j] == 1 && !visited[i][j]) {
                    dfs(grid2,i,j);
                    res++;
                }
            }
        }
        return res;
    }

    public void dfs(int[][] grid, int x, int y) {
        if(x<0||y<0||x>grid.length-1||y>grid[0].length-1||visited[x][y]){
            return ;
        }
        if(grid[x][y]==0)return;
        visited[x][y]=true;
        grid[x][y]=0;
        dfs(grid,x-1,y);
        dfs(grid,x+1,y);
        dfs(grid,x,y+1);
        dfs(grid,x,y-1);
    }
}
相关推荐
中微极客7 小时前
降维算法75倍加速:从PCA到稀疏字典学习的工程实践
人工智能·学习·算法
storyseek8 小时前
前缀和实现Kogge-Stone算法
数据结构·算法
元Y亨H8 小时前
开发者必须掌握的十大核心算法
算法
元Y亨H8 小时前
深度解构:数据结构与算法的理论基石与工程演进
数据结构·算法
元Y亨H8 小时前
数据结构与算法的通俗指南
数据结构·算法
2301_764441339 小时前
用动力学系统(微分方程)为 Kernberg 的客体关系单元提供数学化的操作定义,把“自体—客体“这对心理结构建模成一个二维耦合系统
数据结构·python·算法·数学建模
林泽毅9 小时前
PyTRIO快速入门(二):Datum构建
人工智能·算法·产品
keep intensify9 小时前
最长有效括号
算法·leetcode·动态规划
CoderYanger9 小时前
A.每日一题:1979. 找出数组的最大公约数
java·程序人生·算法·leetcode·面试·职场和发展·学习方法
猫头虎9 小时前
什么是ZCode for GLM-5.2?
开发语言·人工智能·python·科技·算法·ai编程·ai写作