https://leetcode.com/problems/number-of-islands-ii/description/
image.png
这道题我们可以想这样一个问题,如果每丢一块石头,什么时候岛屿会加,什么时候岛屿会减,什么时候岛屿会不加不减。
把这几种情况罗列一下,我们可以发现,丢了一块石头下去。四周都是海,那么岛屿会加。如果周围有陆地,那么岛屿会根据连通的陆地块数减去对应的。那么就是要看一个集合和另一个集合能不能连通起来。我们就能想到并查集。
下面是代码
int[] parent;
int[] rank;
int find(int i){
if(i == parent[i]) return i;
return parent[i] = find(parent[i]);
}
boolean union(int i,int j){
int pi = find(i);
int pj = find(j);
if(pi == pj) return false;
if(rank[pi]>rank[pj]){
parent[pj] = pi;
}else if(rank[pj]>rank[pi]){
parent[pi] = pj;
}else{
parent[pi] = pj;
rank[pi]++;
}
return true;
}
public List<Integer> numIslands2(int m, int n, int[][] positions) {
List<Integer> res = new ArrayList<>();
parent = new int[m*n];
rank = new int[m*n];
Arrays.fill(parent,-1);
int[][] dirs ={{1,0},{0,1},{-1,0},{0,-1}};
int cnt = 0;
for(int[] pos : positions){
int y = pos[0];
int x = pos[1];
if(out(y,x,m,n) || parent[y*n+x]!=-1){
res.add(cnt);
continue;
}
parent[y*n+x]=y*n+x;
cnt++;
for(int[] dir : dirs){
int ny = y+dir[0];
int nx = x+dir[1];
if(out(ny,nx,m,n) || parent[ny*n+nx]==-1) continue;
if(union(y*n+x,ny*n+nx)) cnt--;
}
res.add(cnt);
}
return res;
}
private boolean out(int y,int x,int m,int n){
return y<0 || x<0 || x>=n || y>=m;
}