Bootstrap

代码随想录算法训练营第五十四天|99.岛屿数量 深搜、广搜、100.岛屿的最大面积

99.岛屿数量

在这里插入图片描述

题目链接:99.岛屿数量
文档讲解:代码随想录
状态:不会

深搜

思路:

  1. 遍历网格,发现岛屿:我们需要遍历整个二维网格,检查每一个位置上的元素。如果在遍历过程中遇到陆地(值为1),这意味着我们发现了一个新的岛屿。
  2. 深度优先搜索,标记整个岛屿:为了标记整个岛屿,我们从这个陆地开始,使用深度优先搜索(DFS)将与之相连的所有陆地都标记为已访问过。这样可以确保同一个岛屿的所有部分都被访问到,不会重复计数。
  3. 统计岛屿数量:每当完成一次DFS遍历,就表示已经标记完一个完整的岛屿,所以岛屿数量加1。
  4. 继续遍历:继续遍历网格中的下一个位置,直到所有位置都被检查过。

题解:

public class Main {

    /**
     * 计算岛屿的数量
     *
     * @param grid 输入的二维网格
     * @return 岛屿的数量
     */
    public static int getNum(int[][] grid) {
        int count = 0; // 初始化岛屿数量为0
        int n = grid.length; // 网格的行数
        int m = grid[0].length; // 网格的列数
        for (int i = 0; i < n; i++) { // 遍历每一行
            for (int j = 0; j < m; j++) { // 遍历每一列
                if (grid[i][j] == 1) { // 如果当前位置是陆地
                    dfs(grid, i, j); // 进行深度优先搜索,将连接的所有陆地标记
                    count++; // 每标记完一个岛屿,岛屿数量加1
                }
            }
        }
        return count; // 返回岛屿数量
    }

    /**
     * 深度优先搜索(DFS)函数,用于标记连接的所有陆地
     *
     * @param grid 网格
     * @param x    当前行
     * @param y    当前列
     */
    public static void dfs(int[][] grid, int x, int y) {
        if (!inArea(grid, x, y)) { // 如果坐标不在网格范围内,直接返回
            return;
        }
        if (grid[x][y] != 1) { // 如果当前位置不是陆地(已经是水或者已经标记过),直接返回
            return;
        }
        grid[x][y] = 2; // 将当前陆地标记为2,表示已访问
        // 对当前陆地的上下左右四个方向进行递归搜索
        dfs(grid, x - 1, y);
        dfs(grid, x + 1, y);
        dfs(grid, x, y - 1);
        dfs(grid, x, y + 1);
    }

    /**
     * 判断坐标 (x, y) 是否在网格中
     *
     * @param grid 网格
     * @param x    行坐标
     * @param y    列坐标
     * @return 坐标 (x, y) 是否在网格中
     */
    static boolean inArea(int[][] grid, int x, int y) {
        return 0 <= x && x < grid.length && 0 <= y && y < grid[0].length;
    }

    /**
     * 主函数,读取输入并输出岛屿数量
     *
     * @param args 命令行参数
     */
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in); // 创建扫描器用于读取输入
        int n = scanner.nextInt(); // 读取网格的行数
        int m = scanner.nextInt(); // 读取网格的列数
        int[][] graph = new int[n][m]; // 创建网格
        // 读取网格中的每一个元素
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                graph[i][j] = scanner.nextInt();
            }
        }
        // 输出岛屿的数量
        System.out.println(getNum(graph));
    }
}

广搜

思路:
使用 BFS 进行遍历,从每个未访问过的陆地开始,进行岛屿的搜索。
使用一个队列来存储待处理的陆地节点,并使用一个二维数组来标记已访问过的节点,以避免重复计数。

  1. 初始化:定义方向数组,包括上、下、左、右四个方向的移动。使用队列存储起始节点,并将起始节点标记为已访问。
  2. BFS遍历:从队列中取出节点,检查其四个相邻方向的节点:
    • 如果相邻节点是未访问过的陆地(值为 1),则将其加入队列并标记为已访问。
    • 继续该过程直到队列为空,表示一个完整的岛屿已经被遍历完毕。
  3. 计数:每当从主函数的双重循环中发现未访问的陆地(即值为 1 的格子),则调用 BFS 进行扩展,并将岛屿计数加一。

题解:

  /**
     * 使用BFS计算岛屿数量
     *
     * @param grid    输入的二维网格
     * @param visited 访问标记数组
     * @param x       当前节点行坐标
     * @param y       当前节点列坐标
     */
    static void bfs(int[][] grid, boolean[][] visited, int x, int y) {
        int n = grid.length;
        int m = grid[0].length;
        // 方向数组:下、右、上、左
        int[][] dir = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
        Deque<int[]> deque = new LinkedList<>();
        deque.addLast(new int[]{x, y}); // 将起始节点加入队列
        visited[x][y] = true; // 标记起始节点为已访问

        while (!deque.isEmpty()) {
            int[] point = deque.pollFirst(); // 取出队列首个节点
            int curX = point[0];
            int curY = point[1];

            // 遍历当前节点的四个方向
            for (int i = 0; i < 4; i++) {
                int newX = curX + dir[i][0];
                int newY = curY + dir[i][1];

                // 检查新位置是否在网格范围内,并且是未访问的陆地
                if (newX >= 0 && newX < n && newY >= 0 && newY < m && grid[newX][newY] == 1 && !visited[newX][newY]) {
                    deque.addLast(new int[]{newX, newY}); // 将新位置加入队列
                    visited[newX][newY] = true; // 标记新位置为已访问
                }
            }
        }
    }

    /**
     * 主函数,读取输入并输出岛屿数量
     *
     * @param args 命令行参数
     */
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in); // 创建扫描器用于读取输入
        int n = scanner.nextInt(); // 读取网格的行数
        int m = scanner.nextInt(); // 读取网格的列数
        int[][] graph = new int[n][m]; // 创建网格
        // 读取网格中的每一个元素
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                graph[i][j] = scanner.nextInt();
            }
        }
        boolean[][] visited = new boolean[n][m];
        int count = 0;
        // 遍历每个位置,如果是未访问过的陆地(值为1),则调用bfs进行岛屿扩展,并计数
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (graph[i][j] == 1 && !visited[i][j]) {
                    bfs(graph, visited, i, j); // 对未访问过的陆地进行BFS搜索
                    count++; // 计数岛屿数量
                }
            }
        }
        // 输出岛屿的数量
//        System.out.println(getNum(graph));
        System.out.println(count);
    }

100.岛屿的最大面积

在这里插入图片描述

题目链接:100.岛屿的最大面积
文档讲解:代码随想录
状态:磕磕绊绊做出来了

思路:
在上一题的基础上,每遍历陆地中的一个格子,面积加一,返回最大面积。

dfs题解:

public class Main {

    // 定义方向数组,表示右、下、左、上四个方向
    public static int[][] dir = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}};

    /**
     * 深度优先搜索 (DFS) 方法,计算从 (x, y) 开始的岛屿面积
     *
     * @param grid    二维数组表示的网格
     * @param visited 二维数组标记是否访问过
     * @param x       当前坐标的 x 轴位置
     * @param y       当前坐标的 y 轴位置
     * @return 从 (x, y) 开始的岛屿面积
     */
    public static int dfs(int[][] grid, boolean[][] visited, int x, int y) {
        // 检查是否越界、是否已经访问过、是否是水域
        if (x < 0 || x >= grid.length || y < 0 || y >= grid[0].length || visited[x][y] || grid[x][y] == 0) {
            return 0;
        }

        // 将当前格子标记为已访问,并将其面积记为 1
        int sum = 1;
        visited[x][y] = true;

        // 遍历四个方向,并递归搜索相邻格子
        for (int i = 0; i < 4; i++) {
            int newX = x + dir[i][0];
            int newY = y + dir[i][1];
            sum += dfs(grid, visited, newX, newY);
        }
        return sum;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 读取网格的行数和列数
        int n = scanner.nextInt();
        int m = scanner.nextInt();

        // 初始化网格并读取值
        int[][] grid = new int[n][m];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                grid[i][j] = scanner.nextInt();
            }
        }

        // 初始化访问标记数组
        boolean[][] visited = new boolean[n][m];
        int maxArea = 0;

        // 遍历网格中的每一个格子
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                // 如果当前格子是岛屿且未被访问过,则计算从该格子开始的岛屿面积
                if (!visited[i][j] && grid[i][j] == 1) {
                    maxArea = Math.max(maxArea, dfs(grid, visited, i, j));
                }
            }
        }

        // 输出最大的岛屿面积
        System.out.println(maxArea);
    }
}

bfs题解:

 public static int bfs(int[][] grid) {
        // 使用双端队列来存储待访问的节点
        Deque<int[]> deque = new LinkedList<>();
        // 获取网格的行数和列数
        int n = grid.length;
        int m = grid[0].length;
        // 用于记录最大的岛屿面积
        int maxArea = 0;

        // 遍历网格中的每一个格子
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                // 如果格子中的值为1,表示这是一个岛屿的一部分
                if (grid[i][j] == 1) {
                    // 初始化当前岛屿的面积
                    int sum = 1;
                    // 将当前格子标记为已访问
                    grid[i][j] = 2;
                    // 将当前格子的坐标加入队列
                    deque.addLast(new int[]{i, j});

                    // 进行广度优先搜索
                    while (!deque.isEmpty()) {
                        // 从队列中取出一个格子的坐标
                        int[] point = deque.pollFirst();
                        int x = point[0];
                        int y = point[1];

                        // 遍历该格子周围的四个方向
                        for (int k = 0; k < 4; k++) {
                            int newX = x + dir[k][0];
                            int newY = y + dir[k][1];
                            // 检查新的坐标是否在网格范围内,并且该格子是否未被访问过
                            if (newX >= 0 && newX < n && newY >= 0 && newY < m && grid[newX][newY] == 1) {
                                // 将新的格子标记为已访问
                                grid[newX][newY] = 2;
                                // 将新的格子的坐标加入队列
                                deque.addLast(new int[]{newX, newY});
                                // 增加当前岛屿的面积
                                sum++;
                            }
                        }
                    }
                    // 更新最大的岛屿面积
                    maxArea = Math.max(maxArea, sum);
                }
            }
        }
        // 返回最大的岛屿面积
        return maxArea;
    }
;