题目
给你一个大小为 n x n 二进制矩阵 grid 。最多 只能将一格 0 变成 1 。返回执行此操作后,grid 中最大的岛屿面积是多少?岛屿 由一组上、下、左、右四个方向相连的 1 形成。
分析
经典的图论中连同分量的题目。包含的知识点:
- 基本DFS 框架,marked辅助数组
- 连通分量个数统计:每次dfs返回 做一次统计
- 标识节点属于哪个连通分量
- 每个连通分量的大小
- 本题将一格变成1,把岛屿连接起来,要注意一格将两个方向的岛屿连接起来的时候,这两个方向上的有可能是同一个岛屿,不要重复累加
算法
- dfs 遍历
这一步统计出每个岛屿大小,标记出每个格子所属的岛屿 - 连接
累加一个格子变成1以后可以连接起来的岛屿总大小,注意不同方向上接壤的岛屿可能是同一个岛屿
代码
class Solution {
public int largestIsland(int[][] grid) {
marked = new int[grid.length][grid[0].length];
for (int[] row : marked) {
Arrays.fill(row, -1);
}
int maxIsland = 0;
for (int i = 0; i < grid.length; ++i) {
for (int j = 0; j < grid[i].length; ++j) {
if (grid[i][j] == 0 || marked[i][j] >= 0) continue;
dfs(i, j, grid);
isLands.add(curSize);
maxIsland = Math.max(maxIsland, curSize);
curSize = 0;
}
}
int maxSize = 0;
for (int i = 0; i < grid.length; ++i) {
for (int j = 0; j < grid[i].length; ++j) {
if (grid[i][j] == 1) continue;
Map<Integer, Integer> includes = new HashMap<>();
int[][] dirs = new int[][] {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
for (int[] dir : dirs) {
int ii = i + dir[0];
int jj = j + dir[1];
if (ii >= 0 && ii < grid.length && jj >= 0 && jj < grid[ii].length && marked[ii][jj] != -1) {
includes.put(marked[ii][jj], isLands.get(marked[ii][jj]));
}
}
int size = 1;
for (Map.Entry<Integer, Integer> e : includes.entrySet()) {
size += e.getValue();
}
maxSize = Math.max(maxSize, size);
}
}
return maxSize == 0 ? maxIsland : maxSize;
}
private void dfs(int i , int j, int[][] grid) {
marked[i][j] = isLands.size();
++ curSize;
int[][] dirs = new int[][] {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
for (int[] dir : dirs) {
int ii = i + dir[0];
int jj = j + dir[1];
if (ii >= 0 && ii < grid.length && jj >= 0 && jj < grid[ii].length
&& grid[ii][jj] == 1 && marked[ii][jj] == -1) {
dfs(ii, jj, grid);
}
}
}
private int curSize = 0;
private ArrayList<Integer> isLands = new ArrayList<>();
private int[][] marked;
}