827. 最大人工岛

827. 最大人工岛

问题描述

给你一个大小为 n x n 二进制矩阵 grid最多 只能将一格 0 变成 1

返回执行此操作后,grid 中最大的岛屿面积是多少?

岛屿 由一组上、下、左、右四个方向相连的 1 形成。

示例 1:

输入: grid = [[1, 0], [0, 1]]
输出: 3
解释: 将一格0变成1,最终连通两个小岛得到面积为 3 的岛屿。

示例 2:

输入: grid = [[1, 1], [1, 0]]
输出: 4
解释: 将一格0变成1,岛屿的面积扩大为 4。

示例 3:

输入: grid = [[1, 1], [1, 1]]
输出: 4
解释: 没有0可以让我们变成1,面积依然为 4。

提示:

  • n == grid.length
  • n == grid[i].length
  • 1 <= n <= 500
  • grid[i][j]01

解题思路与代码实现

一次遍历地图,得出各个岛屿的面积,并做编号记录。可以使用map记录,key为坐标点,value为岛屿面积和岛屿编号 。再次遍历地图,遍历0的方格(因为要将0变成1),并统计该1(由0变成的1)周边岛屿面积,将其相邻面积相加在一起(注意不要重复计算),遍历所有 0 之后,就可以得出 选一个0变成1 之后的最大面积。

class Solution {
    private int[][] directions = new int[][] { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } }; // 上下左右方向
    private int currentArea = 0; // 记录本轮dfs岛屿面积
    private LinkedList<String> currentList; // 记录本轮dfs岛屿覆盖的坐标点

    public int largestIsland(int[][] grid) {
        int m = grid.length, n = grid[0].length; // 行数,列数
        boolean[][] visited = new boolean[m][n]; // 标记数组
        int maxArea = 0; // 记录最大岛屿面积,防止全是陆地的边界情况
        int mark = 1; // 岛屿标记mark,防止重复
        Map<String, int[]> map = new HashMap<>(); // 记录非0点坐标及其所在的岛屿面积,key格式为:x,y
        // 双重循环+dfs,记录每个岛屿的面积及其覆盖的坐标点
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (!visited[i][j] && grid[i][j] == 1) { // 非0且未访问过才进行dfs
                    currentList = new LinkedList<>();
                    currentArea = 0;
                    dfs(grid, i, j, visited);
                    // 如果修改1格无法连接两个岛屿,则初始最大面积岛屿即为所求
                    maxArea = Math.max(maxArea, currentArea);
                    // map记录坐标点及其所在岛屿面积的映射
                    while (!currentList.isEmpty() && currentArea > 0) {
                        String key = currentList.removeLast();
                        map.put(key, new int[] { currentArea, mark }); // 携带岛屿标记mark
                    }
                    mark++;
                }
            }
        }

        int res = maxArea; // 记录最终结果
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (!visited[i][j] && grid[i][j] == 0) { // 0且未访问过才进行统计
                    int area = 1;
                    Set<Integer> set = new HashSet<>(); // set配合mark去重
                    for (int k = 0; k < directions.length; k++) {
                        int nextX = i + directions[k][0];
                        int nextY = j + directions[k][1];
                        if (nextX < 0 || nextX >= grid.length || nextY < 0 || nextY >= grid[0].length) { // 判断是否越界
                            continue;
                        }
                        if (grid[nextX][nextY] == 1) {
                            int[] val = map.get(nextX + "," + nextY);
                            if (!set.contains(val[1])) { // mark标记的岛屿,防止重复访问同一岛屿
                                area += val[0];
                                set.add(val[1]);
                            }
                        }
                    }
                    visited[i][j] = true; // 标记已访问
                    res = Math.max(res, area);
                }

            }
        }

        return res;
    }

    private void dfs(int[][] grid, int x, int y, boolean[][] visited) {
        if (visited[x][y]) { // 判断是否访问过
            return;
        }
        currentList.addLast(x + "," + y); // 记录访问过的点
        currentArea++; // 岛屿面积+1
        visited[x][y] = true; // 标记已访问
        for (int i = 0; i < directions.length; i++) {
            int nextX = x + directions[i][0];
            int nextY = y + directions[i][1];
            if (nextX < 0 || nextX >= grid.length || nextY < 0 || nextY >= grid[0].length) { // 判断是否越界
                continue;
            }
            if (grid[nextX][nextY] == 1) { // 非0点才进行dfs
                dfs(grid, nextX, nextY, visited);
            }
        }
    }
}

踩坑点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值