并查集算法
关键思想
fa[i] = j, 表示i节点的父节点为j,初始状态下,fa[i] = i, 表示父节点为自己
关键函数
-
find()方法
逻辑如下:查看x节点父节点是否为自己,若是返回x,若不是则递归调用find(fa[x])去寻找该集合下的根节点root
int find(int x) { return x == fa[x] ? x : (fa[x] = find(fa[x])); }
-
merge()方法
主要逻辑为:找到i、j节点的根节点,将两者建立关联
rank[i]表示i节点的深度(整体呈树形结构)
若x的深度小于等于y,则将y作为x的父节点
反之,x作为y的父节点。如果两边树的深度相同,则y节点深度➕1
void merge(int i, int j) { int x = find(i), y = find(j); if (rank[x] <= rank[y]) fa[x] = y; else fa[y] = x; if (rank[x] == rank[y] && x != y) rank[y]++; }
例题
import java.util.*;
/**
* 现在有107个用户,编号为1- 107,现在已知有m对关系,每一对关系给你两个数x和y,代表编号为x的用户和编号为y的用户是在一个圈子中,例如:A和B在一个圈子中,B和C在一个圈子中,那么A,B,C就在一个圈子中。现在想知道最多的一个圈子内有多少个用户。
*
* 输入描述:
* 第一行输入一个整数T,接下来有T组测试数据。
* 对于每一组测试数据:第一行输入1个整数n,代表有n对关系。
* 接下来n行,每一行输入两个数x和y,代表编号为x和编号为y的用户在同一个圈子里。
* 1 ≤ T ≤ 10
* 1 ≤ n ≤ 105
* 1 ≤ x, y ≤ 107
*
* 输出描述:
* 对于每组数据,输出一个答案代表一个圈子内的最多人数
*/
class Solution1 {
static class Relation {
int x, y;
Relation(int x, int y) {
this.x = x;
this.y = y;
}
}
static Map<Integer, Integer> map = new HashMap<>();
public static int find(int x) {
if (x == map.get(x)) {
return x;
} else {
int rootNode = find(map.get(x));
map.put(x, rootNode);
return rootNode;
}
}
public static void merge(int i, int j) {
int x = find(i), y = find(j);
map.put(x, y); // y as root node
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int t = scanner.nextInt();
for (int i = 0; i < t; i++) {
int n = scanner.nextInt();
int x, y;
map.clear();
ArrayList<Relation> arrayList = new ArrayList<>();
for (int j = 0; j < n; j++) {
x = scanner.nextInt();
y = scanner.nextInt();
arrayList.add(new Relation(x, y));
map.put(x, x);
map.put(y, y);
}
for (Relation relation : arrayList) {
merge(relation.x, relation.y);
}
Map<Integer, Integer> countMap = new HashMap<>();
Iterator<Map.Entry<Integer, Integer>> iterator = map.entrySet().iterator();
for (; iterator.hasNext(); ) {
int root = find(iterator.next().getValue());
int cur = countMap.getOrDefault(root, 0);
countMap.put(root, cur + 1);
}
int max = Integer.MIN_VALUE;
for (Map.Entry<Integer, Integer> entry : countMap.entrySet()) {
if (entry.getValue() > max) max = entry.getValue();
}
System.out.println(max);
}
}
}