leetcode
leetcode 701 ~ 750
最大人工岛

最大人工岛

难度:

标签:

题目描述

代码结果

运行时间: 413 ms, 内存: 27.6 MB


/*
 * 思路:
 * 1. 使用流的方式遍历矩阵中的每一个0,尝试将其变为1并计算岛屿面积。
 * 2. 使用递归计算岛屿面积。
 * 3. 使用流收集最大面积。
 */

import java.util.Arrays;

public class Solution {
    private int n;
    private int[][] grid;
    private final int[] dX = {-1, 1, 0, 0};
    private final int[] dY = {0, 0, -1, 1};

    public int largestIsland(int[][] grid) {
        this.n = grid.length;
        this.grid = grid;

        return Arrays.stream(grid)
                .flatMapToInt(row -> Arrays.stream(row))
                .filter(cell -> cell == 0)
                .map(cell -> {
                    grid[cell / n][cell % n] = 1;
                    int area = Arrays.stream(grid)
                            .mapToInt(row -> Arrays.stream(row)
                                    .map(this::calculateArea)
                                    .max()
                                    .orElse(0))
                            .max()
                            .orElse(0);
                    grid[cell / n][cell % n] = 0;
                    return area;
                })
                .max()
                .orElse(0);
    }

    private int calculateArea(int cell) {
        return Arrays.stream(new int[]{-1, 1, 0, 0})
                .flatMap(dx -> Arrays.stream(new int[]{0, 0, -1, 1})
                        .map(dy -> dfs(cell / n + dx, cell % n + dy, new boolean[n][n])))
                .sum() + 1;
    }

    private int dfs(int x, int y, boolean[][] visited) {
        if (x < 0 || x >= n || y < 0 || y >= n || grid[x][y] == 0 || visited[x][y]) {
            return 0;
        }
        visited[x][y] = true;
        return 1 + Arrays.stream(new int[]{-1, 1, 0, 0})
                .flatMap(dx -> Arrays.stream(new int[]{0, 0, -1, 1})
                        .map(dy -> dfs(x + dx, y + dy, visited)))
                .sum();
    }
}

解释

方法:

这个题解采用了深度优先搜索(DFS)的思路。首先,遍历整个网格,对于每个值为1的格子,执行DFS遍历其连通的1,并标记为一个新的岛屿编号(dum),同时记录该岛屿的面积。接着,再次遍历网格,对于每个值为0的格子,计算若将其变为1后,能够连接到的岛屿的面积之和,更新最大面积。最后返回最大面积。

时间复杂度:

O(n^2)

空间复杂度:

O(n^2)

代码细节讲解

🦆
在执行DFS时,为何选择将已访问的'1'改为岛屿编号'dum'而不是其他标记方式?这种方式在处理复杂网格时有什么优势?
在执行DFS时,将已访问的'1'改为岛屿编号'dum'而不是统一的其他标记(如-1或特定字符),可以在同一次遍历中同时完成标记和岛屿识别。这样可以避免后续再次遍历来确定不同岛屿的归属,提高效率。此外,这种方式可以直接利用岛屿编号来记录和查询每个岛屿的面积,简化数据结构和逻辑处理,尤其在处理复杂或大型网格时,可以有效地管理和更新岛屿相关信息。
🦆
题解中提到对于每个'0'格子,通过计算与其相邻的岛屿面积来更新最大面积。请问如果一个'0'格子相邻四个方向都是不同的岛屿,算法是如何避免重复计算相邻岛屿面积的?
题解中采用了一个列表`tlist`来避免重复计算相邻岛屿面积。每当计算一个0格子相邻的岛屿面积时,首先检查该岛屿编号是否已在`tlist`中记录。如果未记录,则将其面积加到总和中,并把这个编号添加到`tlist`中。这样可以确保即使0格子相邻四个方向为不同岛屿,每个岛屿的面积只被计算一次。
🦆
题解中在所有岛屿标记完成后检查了'dum==1'和'dtom[2]==li*lj'的情况,这两个检查分别处理了什么特殊情况?
这两个检查处理了所有格子都是水(0)和所有格子都是陆地(1)的两种特殊情况。当'dum==1'时,表示没有任何岛屿被标记,即整个网格全是水,返回1因为可以将一个0转换为1形成一个大小为1的岛屿。当'dtom[2]==li*lj'时,表示唯一的岛屿编号为2且面积等于网格的总格数,此时整个网格全是陆地,所以返回这个陆地的面积。
🦆
如果n非常大接近500,递归的DFS方法可能会引起栈溢出。题解是否考虑了这个问题?如果没有,有什么其他方法可以避免这种情况?
题解中用的递归DFS确实可能在非常大的网格中引起栈溢出。为避免这种情况,可以使用迭代的DFS来代替递归DFS。在迭代的DFS中,可以使用一个显式的栈来模拟递归调用栈,这样可以更好地控制栈的大小和避免溢出。另外,也可以考虑使用广度优先搜索(BFS),它通常使用队列来实现,对于大规模数据也较为稳定。

相关问题