图论系列(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);
    }
}
相关推荐
游是水里的游1 小时前
【算法day19】回溯:分割与子集问题
算法
不想当程序猿_1 小时前
【蓝桥杯每日一题】分糖果——DFS
c++·算法·蓝桥杯·深度优先
南城花随雪。1 小时前
单片机:实现FFT快速傅里叶变换算法(附带源码)
单片机·嵌入式硬件·算法
dundunmm1 小时前
机器学习之scikit-learn(简称 sklearn)
python·算法·机器学习·scikit-learn·sklearn·分类算法
古希腊掌管学习的神1 小时前
[机器学习]sklearn入门指南(1)
人工智能·python·算法·机器学习·sklearn
波音彬要多做1 小时前
41 stack类与queue类
开发语言·数据结构·c++·学习·算法
程序员老冯头3 小时前
第十五章 C++ 数组
开发语言·c++·算法
AC使者8 小时前
5820 丰富的周日生活
数据结构·算法
cwj&xyp8 小时前
Python(二)str、list、tuple、dict、set
前端·python·算法
xiaoshiguang313 小时前
LeetCode:222.完全二叉树节点的数量
算法·leetcode