图论系列(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
思路:

当grid[x][y]=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 分钟前
【双机位A卷】华为OD笔试之【排序】双机位A-银行插队【Py/Java/C++/C/JS/Go六种语言】【欧弟算法】全网注释最详细分类最全的华子OD真题题解
java·c语言·javascript·c++·python·算法·华为od
TL滕8 分钟前
从0开始学算法——第一天(认识算法)
数据结构·笔记·学习·算法
小欣加油9 分钟前
leetcode 3318 计算子数组的x-sum I
c++·算法·leetcode·职场和发展
love is sour27 分钟前
聚类(Clustering)详解:让机器自己发现数据结构
算法·支持向量机·聚类
烟袅35 分钟前
LeetCode 142:环形链表 II —— 快慢指针定位环的起点(JavaScript)
前端·javascript·算法
CoovallyAIHub39 分钟前
OCR战场再起风云:LightOnOCR-1B凭什么比DeepSeekOCR快1.7倍?(附演示开源地址)
深度学习·算法·计算机视觉
海琴烟Sunshine1 小时前
leetcode 190. 颠倒二进制位 python
python·算法·leetcode
Xの哲學2 小时前
Linux eMMC子系统深度解析:从硬件协议到内核实现
linux·网络·算法·架构·边缘计算
AI柠檬2 小时前
C语言基于MPI并行计算矩阵的乘法
c语言·c++·算法
lin__ying2 小时前
机器学习-聚类
算法·机器学习