并查集
并查集,用于判断一对元素之间是否相连,他们之间是否相连是动态添加的,这一类问题叫做动态连通性问题。主要执行的操作是
1、合并
2、判断是否处于同一个集合中
并查集使用哈希表或者数组实现,存储的元素用于表示 当前结点 指向的 根结点,初始化的时候根结点指向自己。
合并操作就是把 一个集合的根结点指向另一个集合的根结点,两个元素的根结点一样则代表元素 处于同一个集合之中。
这种表示 不相交集合的方法称之为 代表元法,每个结点的根结点作为一个集合的代表元
并查集:最常见的使用就是kruskal最小生成树算法。也就意味着你首先要知道你的顶点的个数
并查集常见的优化方案
1、路径压缩(隔代压缩、完全压缩)
2、按秩合并
下面展示一道经典并查集例题
输入:[“a==b”,“b!=a”]
输出:false
解释:如果我们指定,a = 1 且 b = 1,那么可以满足第一个方程,但无法满足第二个方程。没有办法分配变量同时满足这两个方程。
以下代码是leetcode官方题解,我只是加上了个人注释方便理解
class Solution {
public boolean equationsPossible(String[] equations) {
/**
* 1、初始化并查集
* 确定顶点个数,a-z为26个字符
* 根结点初始为本身,将26个字符按照顺序编程数字方便对比
*/
int parents[] = new int[26];
for(int i=0;i<26;i++){
parents[i]=i;
}
//2、遍历 进行等价合并操作
for(String s:equations){
if(s.charAt(1)=='='){
int index1 = s.charAt(0)-'a';
int index2 = s.charAt(3)-'a';
union(parents,index1,index2); //合并
}
}
//3、对比 验证是否存在矛盾
for(String s:equations){
if(s.charAt(1)=='!'){
int index1 = s.charAt(0)-'a';
int index2 = s.charAt(3)-'a';
//注意此处是 a!=b 则若两者拥有相同的根结点则说明两者在同一集合中矛盾
if(find(parents,index1) == find(parents,index2))
return false;
}
}
return true;
}
//合并
public void union(int[] parents,int index1,int index2){
/**
* find(parent, index1) 找到index1对应的根结点
* find(parent, index2) 找到index2对应的根结点
* 合并
* 其中parent[i]存放的是该结点的根结点 , i则代表了该结点是第几个结点
*/
parents[find(parents,index1)] = find(parents,index2);
}
//查询根结点, 并进行路径压缩(这里采用的完全压缩)
//根结点 数组下标必对应数组元素
public int find(int[] parents,int index){
while(parents[index]!=index){
parents[index] = parents[parents[index]];
index = parents[index];
}
return index;
}
}