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]
为0
或1
做题结果
成功,会并查集的话这题就很简单
步骤
1. 初始化父节点,根节点大小
2. 对相邻的 1 进行连接
3. 对 0 位置处理,连接上下左右4块后的最大值,特别的,自己算1
细节
1. 全 1 处理,返回 n*n
2. 全 0 处理,返回 1(这步可以不处理)
3. 考虑上下左右块相邻的情况,针对父节点去重
class Solution {
int[] parent;
int[] sizes;
int n;
public int largestIsland(int[][] grid) {
n = grid.length;
parent = new int[n*n];
sizes = new int[n*n];
boolean allZero = true;
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
int v = flat(i,j);
parent[v] = v;
sizes[v] = grid[i][j];
allZero = allZero && sizes[v]==0;
}
}
if(allZero) return 1;
int[] directions = new int[]{0,1,0,-1,0};
for(int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if(grid[i][j]!=1) continue;
int t = flat(i,j);
for(int k = 0; k < 4; k++){
int x = i+directions[k];
int y = j+directions[k+1];
if(x>=0&&x<n&&y>=0&&y<n&&grid[x][y]==1){
connect(t,flat(x,y));
}
}
}
}
if(sizes[root(0)]==n*n) return n*n;
int ans = 0;
for(int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if(grid[i][j]==1) continue;
int size = 1;
Set<Integer> p = new HashSet<>();
for(int k = 0; k < 4; k++) {
int x = i + directions[k];
int y = j + directions[k + 1];
if(x>=0&&x<n&&y>=0&&y<n && p.add(root(flat(x,y)))){
size += sizes[root(flat(x,y))];
}
}
ans = Math.max(size,ans);
}
}
return ans;
}
private int flat(int x, int y){
return x*n+y;
}
public void connect(int a, int b){
int rootA = root(a);
int rootB = root(b);
if(rootA == rootB) return;
if(sizes[rootA]>sizes[rootB]){
sizes[rootA]+=sizes[rootB];
parent[rootB] = rootA;
}else{
sizes[rootB]+=sizes[rootA];
parent[rootA] = rootB;
}
}
private int root(int v){
while (parent[v]!=v){
parent[v] = parent[parent[v]];
v = parent[v];
}
return v;
}
}