例题
class Solution {
public int longestConsecutive(int[] nums) {
if (nums.length == 0) return 0;
// 首次遍历,与邻居结盟
UnionFind uf = new UnionFind(nums);
for (int v : nums)
uf.union(v, v + 1); // uf.union() 结盟
// 二次遍历,记录领队距离
int max = 1;
for (int v : nums)
max = Math.max(max, uf.find(v) - v + 1); // uf.find() 查找领队
return max;
}
}
class UnionFind {
private int count;
private Map<Integer, Integer> parent; // (curr, leader)
UnionFind(int[] arr) {
parent = new HashMap<>();
for (int v : arr)
parent.put(v, v); // 初始时,各自为战,自己是自己的领队
count = parent.size(); // 而非 arr.length,因可能存在同 key 的情况
// 感谢 [@icdd](/u/icdd/) 同学的指正
}
// 结盟
void union(int p, int q) {
// 不只是 p 与 q 结盟,而是整个 p 所在队伍 与 q 所在队伍结盟
// 结盟需各领队出面,而不是小弟出面
Integer rootP = find(p), rootQ = find(q);
if (rootP == rootQ) return;
if (rootP == null || rootQ == null) return;
// 结盟
parent.put(rootP, rootQ); // 谁大听谁
// 应取 max,而本题已明确 p < q 才可这么写
// 当前写法有损封装性,算法题可不纠结
count--;
}
// 查找领队
Integer find(int p) {
if (!parent.containsKey(p))
return null;
// 递归向上找领队
int root = p;
while (root != parent.get(root))
root = parent.get(root);
// 路径压缩:扁平化管理,避免日后找领队层级过深
while (p != parent.get(p)) {
int curr = p;
p = parent.get(p);
parent.put(curr, root);
}
return root;
}
}
class Solution {
class UnionFind {
int count;
int[] parent;
int[] rank;
public UnionFind(char[][] grid) {
count = 0;
int m = grid.length;
int n = grid[0].length;
parent = new int[m * n];
rank = new int[m * n];
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (grid[i][j] == '1') {
parent[i * n + j] = i * n + j;
++count;
}
rank[i * n + j] = 0;
}
}
}
public int find(int i) {
if (parent[i] != i) parent[i] = find(parent[i]);
return parent[i];
}
public void union(int x, int y) {
int rootx = find(x);
int rooty = find(y);
if (rootx != rooty) {
if (rank[rootx] > rank[rooty]) {
parent[rooty] = rootx;
} else if (rank[rootx] < rank[rooty]) {
parent[rootx] = rooty;
} else {
parent[rooty] = rootx;
rank[rootx] += 1;
}
--count;
}
}
public int getCount() {
return count;
}
}
public int numIslands(char[][] grid) {
if (grid == null || grid.length == 0) {
return 0;
}
int nr = grid.length;
int nc = grid[0].length;
int num_islands = 0;
UnionFind uf = new UnionFind(grid);
for (int r = 0; r < nr; ++r) {
for (int c = 0; c < nc; ++c) {
if (grid[r][c] == '1') {
grid[r][c] = '0';
if (r - 1 >= 0 && grid[r-1][c] == '1') {
uf.union(r * nc + c, (r-1) * nc + c);
}
if (r + 1 < nr && grid[r+1][c] == '1') {
uf.union(r * nc + c, (r+1) * nc + c);
}
if (c - 1 >= 0 && grid[r][c-1] == '1') {
uf.union(r * nc + c, r * nc + c - 1);
}
if (c + 1 < nc && grid[r][c+1] == '1') {
uf.union(r * nc + c, r * nc + c + 1);
}
}
}
}
return uf.getCount();
}
}