題目地址:
https://leetcode.com/problems/number-of-islands-ii/
給定一個二維零矩陣,再給點一個數組,數組每個位置是個長爲的整數數組,是矩陣裏的一個座標。遍歷數組的同時,會把矩陣相應座標位置上的變爲。要求在線計算遍歷數組的時候連通塊(島嶼)的數量。
思路是並查集。在遍歷數組的時候,取出座標,如果矩陣在該位置已經有島嶼則略過(這裏主要是預防數組裏有重複座標,也就是同一個位置變了兩次);如果沒有島嶼,則先將島嶼數加,然後將這個島嶼和四周的島嶼全做一遍union,每union一次就要將島嶼數減去,同時動態將島嶼數加入最後答案即可。代碼如下:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Solution {
class UnionFind {
private int[] parent, rank;
private int count;
public UnionFind(int size) {
parent = new int[size];
rank = new int[size];
// 先標記爲-1,表示這個位置沒有陸地
Arrays.fill(parent, -1);
Arrays.fill(rank, 1);
}
public int find(int p) {
if (p != parent[p]) {
parent[p] = find(parent[p]);
}
return parent[p];
}
public void union(int p, int q) {
// 如果有一個不是陸地,則不用union
if (parent[p] == -1 || parent[q] == -1) {
return;
}
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
count--;
}
public int getCount() {
return count;
}
private void add(int x, int y, int m, int n) {
int pos = mapToInt(x, y, n);
// 已經是陸地了,就不用重複變爲陸地了
if (parent[pos] != -1) {
return;
}
// 先變爲陸地
parent[pos] = pos;
// 先假設這個陸地構成了一個新的連通塊,將島嶼數加1,後面union的時候再減
count++;
// 四個方向上做union
if (x + 1 < m) {
union(mapToInt(x, y, n), mapToInt(x + 1, y, n));
}
if (x - 1 >= 0) {
union(mapToInt(x, y, n), mapToInt(x - 1, y, n));
}
if (y + 1 < n) {
union(mapToInt(x, y, n), mapToInt(x, y + 1, n));
}
if (y - 1 >= 0) {
union(mapToInt(x, y, n), mapToInt(x, y - 1, n));
}
}
private int mapToInt(int x, int y, int n) {
return x * n + y;
}
}
public List<Integer> numIslands2(int m, int n, int[][] positions) {
List<Integer> res = new ArrayList<>();
UnionFind uf = new UnionFind(m * n);
for (int i = 0; i < positions.length; i++) {
int x = positions[i][0], y = positions[i][1];
uf.add(x, y, m, n);
res.add(uf.getCount());
}
return res;
}
}
時間複雜度(是iterative logarithm),空間複雜度。