基本概念
- 并查集是一种数据结构
- 并查集这三个字,一个字代表一个意思。
- 并(Union),代表合并
- 查(Find),代表查找
- 集(Set),代表这是一个以字典为基础的数据结构,它的基本功能是合并集合中的元素,查找集合中的元素
- 并查集的典型应用是有关连通分量的问题
- 并查集解决单个问题(添加,合并,查找)的时间复杂度都是O(1)。
因此,并查集可以应用到在线算法中。
数据结构
- 并查集跟树有些类似,只不过她跟树是相反的。在树这个数据结构里面,每个节点会记录它的子节点。在并查集里,每个节点会记录它的父节点。
完整模板
class UnionFind {
//记录父节点
private Map<Integer,Integer> father;
public UnionFind() {
father = new HashMap<Integer,Integer>();
}
//向并查集里面添加元素
public void add(int x) {
if (!father.containsKey(x)) {
father.put(x, null);
}
}
//将A,B(不共根节点的两节点)插入到一个集合中
public void merge(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY){
father.put(rootX,rootY);
}
}
public int find(int x) {
//寻找根节点
int root = x;
while(father.get(root) != null){
root = father.get(root);
}
//路径压缩,防止并查集退化成链表
while(x != root){
int original_father = father.get(x);
father.put(x,root);
x = original_father;
}
return root;
}
//判断x, y 的是否相连(根节点是否相同)
public boolean isConnected(int x, int y) {
return find(x) == find(y);
}
}
例题:lc547.省份数量
class UnionFind{
// 记录父节点
private Map<Integer, Integer> father;
// 记录集合的数量
private int numOfSets = 0;
public UnionFind() {
father = new HashMap<Integer, Integer>();
numOfSets = 0;
}
public void add(int x) {
if (!father.containsKey(x)) {
father.put(x, null);
numOfSets++;
}
}
public void merge(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY) {
father.put(rootX, rootY);
numOfSets--;
}
}
public int find(int x) {
int root = x;
while (father.get(root) != null) {
root = father.get(root);
}
while (x != root) {
int original_father = father.get(x);
father.put(x, root);
x = original_father;
}
return root;
}
public boolean isConnected(int x, int y) {
return find(x) == find(y);
}
public int getNumOfSets(){
return numOfSets;
}
}
class Solution {
public int findCircleNum(int[][] isConnected) {
UnionFind uf = new UnionFind();
for (int i = 0; i < isConnected.length; i++) {
uf.add(i);
for (int j = 0; j < i; j++) {
if (isConnected[i][j] == 1) {
uf.merge(i, j);
}
}
}
return uf.getNumOfSets();
}
}