题目地址:
https://www.lintcode.com/problem/number-of-islands-ii/description
给定一个二维 0 0 0矩阵,再给定一系列坐标,每次操作都将某个坐标位置的 0 0 0改为 1 1 1,要求动态返回 1 1 1连通块的数量。
思路是并查集。一开始先记连通块数量为 0 0 0,同时开一个数组记录某个位置是否已经是 1 1 1,接着每遍历一个坐标。如果该坐标位置已经是 1 1 1则略过,否则将这个位置标记为是 1 1 1,将连通块数目加 1 1 1,接着和其四个邻居上的 1 1 1做union操作,每union一次就将连通块数目减少 1 1 1,并及时返回连通块数目。代码如下:
import java.util.ArrayList;
import java.util.List;
public class Solution {
class UnionFind {
private int[] parent, rank;
private boolean[] visited;
private int group;
private int cols, rows;
public UnionFind(int n, int rows, int cols) {
parent = new int[n];
rank = new int[n];
// 记录某个位置是否已经是1
visited = new boolean[n];
for (int i = 0; i < n; i++) {
parent[i] = i;
rank[i] = 1;
}
this.rows = rows;
this.cols = cols;
}
public int find(int p) {
if (p != parent[p]) {
parent[p] = find(parent[p]);
}
return parent[p];
}
public void union(int p, int q) {
int pRoot = find(p), qRoot = find(q);
if (pRoot == qRoot) {
return;
}
if (rank[pRoot] < rank[qRoot]) {
parent[pRoot] = qRoot;
} else if (rank[pRoot] > rank[qRoot]) {
parent[qRoot] = pRoot;
} else {
parent[pRoot] = qRoot;
rank[qRoot]++;
}
// union一次连通块数目就减少1
group--;
}
public void add(Point p) {
int x = p.x, y = p.y;
if (visited[getId(x, y)]) {
return;
}
visited[getId(x, y)] = true;
group++;
if (x > 0 && visited[getId(x - 1, y)]) {
union(getId(x, y), getId(x - 1, y));
}
if (x < rows - 1 && visited[getId(x + 1, y)]) {
union(getId(x, y), getId(x + 1, y));
}
if (y > 0 && visited[getId(x, y - 1)]) {
union(getId(x, y), getId(x, y - 1));
}
if (y < cols - 1 && visited[getId(x, y + 1)]) {
union(getId(x, y), getId(x, y + 1));
}
}
// 将二维坐标映射到一维去
private int getId(int x, int y) {
return cols * x + y;
}
public int getGroup() {
return group;
}
}
/**
* @param n: An integer
* @param m: An integer
* @param operators: an array of point
* @return: an integer array
*/
public List<Integer> numIslands2(int n, int m, Point[] operators) {
// write your code here
List<Integer> res = new ArrayList<>();
if (operators == null || operators.length == 0) {
return res;
}
UnionFind uf = new UnionFind(n * m, n, m);
for (Point operator : operators) {
uf.add(operator);
res.add(uf.getGroup());
}
return res;
}
}
class Point {
int x, y;
Point() {
x = y = 0;
}
Point(int x, int y) {
this.x = x;
this.y = y;
}
}
时间复杂度 O ( k log k ) O(k\log k) O(klogk)( k k k为操作次数),空间复杂度 O ( m n ) O(mn) O(mn)。