题解
思路:
翻转0==>1后,需要将周围存在的岛屿的面积做累加。
因此为了方便,我们不在每一次翻转后都去计算一遍岛屿的面积,这样会使得复杂度大幅提升。
可以考虑第一次便利时,我们就将岛屿编号,并记录每个编号岛屿的面积,这样,下次找到岛屿时通过编号可以直接获取面积。
那么问题又来了,如何知道当前格子0
附近的岛屿1
是哪个编号的岛屿呢?这需要去对原地图进行部分的修改,将原来的岛屿修改为对应的编号,我们做如下修改:
- 每个连通的岛屿给不同的编号
- 岛屿周围的一圈赋值为
-1
因为只翻转一格,所以如果想获得岛屿的最大值,一定是在岛屿周围一圈的格子翻转
- 其余格子值不变
修改方式如图所示:
问题就转变为几个小问题了:
- 计算每个岛屿的面积并编号。可以利用DFS计算岛屿面积,并通过一个值记录当前岛屿的最大编号,并利用
HasMap
记录编号岛屿对应的面积。 - 转换完成后,遍历寻找
-1
的格子,找到周围所有不同编号的岛屿,计算面积之和并加1,取最大值。 - 考虑极端情况,整个区域都是
1
,返回结果为n*n
;整个区域都为0
,返回结果为1
实现代码如下:
public class Solution {
private final int[] directionX = {-1,0,1,0};
private final int[] directionY = {0,1,0,-1};
private int[][] idGrid;
private Map<Integer, Integer> id2Area = new HashMap<>();
private int n;
private int curArea;
public int largestIsland(int[][] grid) {
//1. 通过DFS给每个岛屿编号,同时计算面积
int count = 1;
int ans = 0;
int n = grid.length;
this.n = n;
idGrid = new int[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] == 1 && idGrid[i][j]==0){
// 清空上次岛屿的面积
curArea = 0;
//计算当前岛屿面积
dfs(grid, i, j, count);
id2Area.put(count, curArea);
count++;
ans = Math.max(ans, curArea); //考虑地图填满的情况,没有0->1的操作空间
}
}
}
//在idGrid上做文章,-1的部分为岛屿的边界
//0的部分没有用
//大于0的部分为岛屿
int newX, newY;
HashSet<Integer> idSet = new HashSet<>();
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (idGrid[i][j] < 0){
//说明四个方向上至少有一个岛屿
//可以做以下的统一处理
//获取4个方向上岛屿的面积,如果不存在岛屿,面积值设置为0,
//把这四个方向上岛屿的面积全部加起来再+1即可
//拿到四个岛屿的编号,可能会存在重复的,使用集合
idSet.clear();
for (int k = 0; k < 4; k++) {
newX = i+directionX[k];
newY = j+directionY[k];
if (newX>=0 && newX<n && newY>=0 && newY<n){
idSet.add(idGrid[newX][newY]);
}
}
//把这几个编号的面积全部加上
int tempArea = 0;
for (Integer id : idSet) {
tempArea += (id2Area.getOrDefault(id, 0));
}
ans = Math.max(ans, tempArea+1);
}
}
}
//考虑没有岛屿的情况
return ans==0 ? 1:ans;
}
private void dfs(int[][] grid, int x, int y, int id){
idGrid[x][y] = id;
curArea++;
int newX, newY;
for (int i=0; i<4; i++){
newX = x+directionX[i];
newY = y+directionY[i];
if (newX>=0 && newX < n && newY>=0 && newY<n){
if(grid[newX][newY] == 1 && idGrid[newX][newY]==0){
dfs(grid, newX, newY, id);
} else if(grid[newX][newY] == 0) {
//岛屿周围做一个标记
idGrid[newX][newY] = -1;
}
}
}
}
}