它是一种维护集合的数据结构,它的名字"并" "查" "集" 。即 union / find / set。 并查集产生的每个集合都是一棵树(tree) 。基本操作:
1.合并两个集合union。
2.判断两个元素是否在一个集合中find。
实现:
利用一个数组int father[N];其中父节点自身也在1-N之中
用来记录父节点:即father[i]表示的i节点的父亲节点。当a和b的father[a]==father[b]时,a和b才是联通的。
初始化:
void init(int fa[], int n){
for(int i = 0; i < n; i ++){
fa[i] = i;//令它成为-1也可以
}
}
find操作,查找并返回包含元素x的树的根:
int findFather(int x){
while(x != father[x]){// 如果是-1则此处为father[x] >= 0
x = father[x];//获得父亲节点
}
return x;
}
合并两个不相交的子集合 :
void Union(int fa[], int root1, int root2){
int f1 = findFather(root1);
int f2 = findFather(root2);
if(f1 != f2){
//即表示f2的父亲节点是father[f1]
fa[f1] = f2;
}
}
利用并查集解决问题:leetcode 990. 等式方程的可满足性
题目描述:
给定一个由表示变量之间关系的字符串方程组成的数组,每个字符串方程 equations[i] 的长度为 4,并采用两种不同的形式之一:"a==b" 或 "a!=b"。在这里,a 和 b 是小写字母(不一定不同),表示单字母变量名。只有当可以将整数分配给变量名,以便满足所有给定的方程时才返回 true,否则返回 false。
分析:先根据等式条件建立起连接关系(并查集),然后在不等条件下,如果两个变量名对应树的root的index是相同的,即和之前两变量名在等式条件的关系冲突,即返回false。
class Solution {
public:
vector<int> parent;
int find(int x){
while(x != parent[x]){
x = parent[x];//一层一层的往上找
}
return x;
}
bool equationsPossible(vector<string>& equations) {
parent = vector<int>(26);
//初始化
for(int i = 0; i < 26; i ++){
parent[i] = i;
}
for(const string& s : equations){
if(s[1] == '='){//==
int idx1 = find(s[0] - 'a');
int idx2 = find(s[3] - 'a');
if(idx1 != idx2){
parent[idx2] = idx1;
}
}
}
for(const string& s : equations){
if(s[1] == '!'){//!=
int idx1 = find(s[0] - 'a');
int idx2 = find(s[3] - 'a');
if(idx1 == idx2){
return false;
}
}
}
return true;
}
};