代码随想录算法训练营第 50 天 | 99. 岛屿数量、100. 岛屿的最大面积

99. 岛屿数量

题目链接

思路:
遍历每个地方,如果该处为陆地,且未访问过。将结果加 1.并将该处所连的陆地全部标记为已访问。

方法一
dfs ——先格子赋值为 true,再进入 dfs 函数。(dfs 隐式终止条件)
(实质是遍历相邻的 4 个节点)

import java.util.*;

public class Main {
    public static int[][] dir = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();

        int[][] grid = new int[n][m];

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                grid[i][j] = sc.nextInt();
            }
        }

        int result = 0;
        boolean[][] visited = new boolean[n][m];

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (grid[i][j] == 1 && !visited[i][j]) {
                    result++;
                    visited[i][j] = true; // 先赋值为 true,再进入 dfs 函数
                    dfs(grid, visited, i, j);
                }
            }
        }

        System.out.println(result);
    }

    public static void dfs(int[][] grid, boolean[][] visited, int x, int y) {
        for (int i = 0; i < 4; i++) {
            int nextX = dir[i][0] + x;
            int nextY = dir[i][1] + y;
            if (nextX < 0 || nextX >= grid.length || nextY < 0 || nextY >= grid[0].length) {
                continue;
            }
            if (grid[nextX][nextY] == 1 && !visited[nextX][nextY]) { // 必须是未访问过的陆地,递归终止条件隐含在此
                visited[nextX][nextY] = true; // 先赋值为 true,再进入 dfs 函数
                dfs(grid, visited, nextX, nextY);
            }
        }
    }
}

方法二
dfs ——判断完终止条件后,再赋值为 true。(dfs 显式终止条件)
(实质是从当前节点开始)

import java.util.*;

public class Main {
    public static int[][] dir = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();

        int[][] grid = new int[n][m];

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                grid[i][j] = sc.nextInt();
            }
        }

        int result = 0;
        boolean[][] visited = new boolean[n][m];

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (grid[i][j] == 1 && !visited[i][j]) {
                    result++;
                    dfs(grid, visited, i, j);
                }
            }
        }

        System.out.println(result);
    }

    public static void dfs(int[][] grid, boolean[][] visited, int x, int y) {
        if (grid[x][y] == 0 || visited[x][y]) { // 当不是陆地或者已经访问过就退出
            return;
        }
        
        visited[x][y] = true; // 判断完终止条件后,再赋值为 true
        
        for (int i = 0; i < 4; i++) {
            int nextX = dir[i][0] + x;
            int nextY = dir[i][1] + y;
            if (nextX < 0 || nextX >= grid.length || nextY < 0 || nextY >= grid[0].length) {
                continue;
            }
            dfs(grid, visited, nextX, nextY); // 不用判断陆地和访问,直接 dfs
        }
    }
}

方法三
bfs

重点:队列刚一放进去元素,visited 数组就要立马标记为 true。

import java.util.*;

public class Main {
    public static int[][] dir = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();

        int[][] grid = new int[n][m];

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                grid[i][j] = sc.nextInt();
            }
        }

        int result = 0;
        boolean[][] visited = new boolean[n][m];

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (grid[i][j] == 1 && !visited[i][j]) {
                    result++;
                    bfs(grid, visited, i, j);
                }
            }
        }

        System.out.println(result);
    }

    public static void bfs(int[][] grid, boolean[][] visited, int x, int y) {
        Queue<int[]> queue = new ArrayDeque<>();
        queue.offer(new int[] {x, y});
        visited[x][y] = true; // 队列刚一放进去元素,visited 数组就要立马标记为 true

        while (!queue.isEmpty()) {
            int[] cur = queue.poll();
            for (int i = 0; i < 4; i++) {
                int nextX = dir[i][0] + cur[0];
                int nextY = dir[i][1] + cur[1];

                // 判断未越界
                if (nextX < 0 || nextX >= grid.length || nextY < 0 || nextY >= grid[0].length) {
                    continue;
                }

                // 判断为陆地,且未访问过
                if (grid[nextX][nextY] == 1 && !visited[nextX][nextY]) {
                    queue.offer(new int[] {nextX, nextY});
                    visited[nextX][nextY] = true; // 队列刚一放进去元素,visited 数组就要立马标记为 true
                }
            }
        }
    }
}

优化:
dfs 或 bfs 时,可以只搜右下的格子。

100. 岛屿的最大面积

题目链接

思路和上题几乎一样,dfs 和 bfs 皆可,只需要把统计岛屿数量改成统计岛屿最大面积。

方法一
dfs ——先格子赋值为 true,再进入 dfs 函数。(dfs 隐式终止条件)
(实质是遍历相邻的 4 个节点)

import java.util.*;

public class Main {
    public static int[][] dir = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
    public static int count; // 统计单块区域面积

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();

        int[][] grid = new int[n][m];

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                grid[i][j] = sc.nextInt();
            }
        }

        int result = 0; // 统计最大面积
        boolean[][] visited = new boolean[n][m];

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (grid[i][j] == 1 && !visited[i][j]) {
                    count = 1; // 初始化为 1
                    visited[i][j] = true; // 先赋值为 true,再进入 dfs 函数
                    dfs(grid, visited, i, j);
                    result = Math.max(result, count);
                }
            }
        }

        System.out.println(result);
    }

    public static void dfs(int[][] grid, boolean[][] visited, int x, int y) {
        for (int i = 0; i < 4; i++) {
            int nextX = dir[i][0] + x;
            int nextY = dir[i][1] + y;
            if (nextX < 0 || nextX >= grid.length || nextY < 0 || nextY >= grid[0].length) {
                continue;
            }
            if (grid[nextX][nextY] == 1 && !visited[nextX][nextY]) { // 必须是未访问过的陆地,递归终止条件隐含在此
                count++; // 先 ++,再进入 dfs
                visited[nextX][nextY] = true; // 先赋值为 true,再进入 dfs 函数
                dfs(grid, visited, nextX, nextY);
            }
        }
    }
}

方法二
dfs ——判断完终止条件后,再赋值为 true。(dfs 显式终止条件)
(实质是从当前节点开始)

import java.util.*;

public class Main {
    public static int[][] dir = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
    public static int count; // 统计单块区域面积

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();

        int[][] grid = new int[n][m];

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                grid[i][j] = sc.nextInt();
            }
        }

        int result = 0; // 统计最大面积
        boolean[][] visited = new boolean[n][m];

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (grid[i][j] == 1 && !visited[i][j]) {
                    count = 0; // 因为是先进入 dfs 再 count++,所以这里要赋值为 0
                    dfs(grid, visited, i, j);
                    result = Math.max(result, count);
                }
            }
        }

        System.out.println(result);
    }

    public static void dfs(int[][] grid, boolean[][] visited, int x, int y) {
        if (grid[x][y] == 0 || visited[x][y]) { // 当不是陆地或者已经访问过就退出
            return;
        }
        count++; // 先进入 dfs 再 count++
        visited[x][y] = true; // 先进入该格子再赋值为 true

        for (int i = 0; i < 4; i++) {
            int nextX = dir[i][0] + x;
            int nextY = dir[i][1] + y;
            if (nextX < 0 || nextX >= grid.length || nextY < 0 || nextY >= grid[0].length) {
                continue;
            }
            dfs(grid, visited, nextX, nextY); // 不用判断陆地和访问,直接 dfs
        }
    }
}

方法三:
以上两种 dfs 方法二合一。进入格子后立即赋为 true

import java.util.*;

public class Main {
    public static int[][] dir = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
    public static int count; // 统计单块区域面积

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();

        int[][] grid = new int[n][m];

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                grid[i][j] = sc.nextInt();
            }
        }

        int result = 0; // 统计最大面积
        boolean[][] visited = new boolean[n][m];

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (grid[i][j] == 1 && !visited[i][j]) {
                    count = 1; // 初始化为 1
                    dfs(grid, visited, i, j);
                    result = Math.max(result, count);
                }
            }
        }

        System.out.println(result);
    }

    public static void dfs(int[][] grid, boolean[][] visited, int x, int y) {
        visited[x][y] = true; // 进入后立即设为 true
        
        for (int i = 0; i < 4; i++) {
            int nextX = dir[i][0] + x;
            int nextY = dir[i][1] + y;
            if (nextX < 0 || nextX >= grid.length || nextY < 0 || nextY >= grid[0].length) {
                continue;
            }
            if (grid[nextX][nextY] == 1 && !visited[nextX][nextY]) { // 必须是未访问过的陆地,递归终止条件隐含在此
                count++; // 先 ++,再进入 dfs
                dfs(grid, visited, nextX, nextY);
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值