并查集详解(超级简单有趣~~就学会了)
LeetCode Union-Find(并查集) 专题(一)
并查集主要涉及到两种操作,合并和查找。
实现一个并查集的时候首先要考虑的就是存储结构,数组,链表,哈希表。
数组
步骤:
1.初始化,让每个人都是独立的
2.合并:
2.1找到每个人的顶头上司,返回结果
2.2对返回的结果进行判断,有两种情况: 1这一组的人的上司是同一个人; 2这一组的人的上司不是同一个人,那就选择一个人当另一个人的上司;.
主要应用于可以用一维数组来表示集合关系的题目,如
LeetCode上的朋友圈
虽然输入是一个二维数组,但是这个二维数组表示的是学生之间的朋友关系,可以用一维数组来表示他们属于哪个朋友圈 (也就是找一个这个朋友圈的代表出来,所有跟他有关的人的num[i]都是这个人)
这个是比较经典的并查集的写法:
class Solution {
public:
struct UF{
UF(int n){//先让所有人都没有朋友
nums.resize(n);
for(int i=0;i<n;++i){
nums[i]=i;
}
setnum=n;
}
void union1(int i,int j){
int fi=find(i),fj=find(j);
if(fi==fj)return ;
else {
nums[fi]=fj;//将找到的最终的老大放到明面上
setnum--;
}
}
int find(int a){//找到组代表,这里不进行替换
int i=a,j=a;
while(nums[i]!=i)i=nums[i];
return i;
}
vector<int>nums;
int setnum;
};
int findCircleNum(vector<vector<int>>& M) {
UF uf_set(M.size());
for(int i=0;i<M.size();++i){
for(int j=0;j<M[0].size();++j){
if(M[i][j]==1)
uf_set.union1(i,j);
}
}
return uf_set.setnum;
}
};
LeetCode上的冗余连接
这题的主要思想就是:当有一对端点的老大是同一个人的时候,就说明是有环的
代码是简化的并查集
class Solution {
public:
int m_find(int n,vector<int>&rp){
while(n!=rp[n])
n=rp[n];
return n;
}
vector<int> findRedundantConnection(vector<vector<int>>& edges) {
vector<int>uf(edges.size()+1);
for(int i=0;i<uf.size();++i){
uf[i]=i;
}
for(auto tmp:edges){
int n1=m_find(tmp[0],uf);
int n2=m_find(tmp[1],uf);
if(n1==n2)return tmp;
else uf[n1]=n2;
}
return {0,0};
}
};
哈希表
对于无法用数组下标和数字来表示对应关系的数据,可以选择构造哈希表
如Leecode 婴儿名字
省略掉输入输出的处理之后,这道题实际上是用两个哈希表来做的,先对名字对进行哈希表cp的构造,再根据名字对进行哈希表fre的构造
class Solution {
public:
unordered_map<string,int>fre;//放字典序最小的名字及所有相似名字出现频率之和
unordered_map<string,string>cp;
string m_find(string n){
if(cp.count(n)==0)
return n;
string root=m_find(cp[n]);
cp[n]=root;
return root;
}
void m_union(string n1,string n2){
n1=m_find(n1);
n2=m_find(n2);
if(n1!=n2){
if(n1>n2)
cp[n1]=n2;
else
cp[n2]=n1;
}
}
vector<string> trulyMostPopular(vector<string>& names, vector<string>& syn) {
for(int i=0;i<syn.size();++i){
int pos=syn[i].find(',');
string n1 = syn[i].substr(1, pos - 1);
string n2 = syn[i].substr(pos + 1, syn[i].size() - pos - 2);
m_union(n1,n2);
}
for(int i=0;i<names.size();++i){
int pos=names[i].find('(');
string n1 = names[i].substr(0, pos);
string n2 = names[i].substr(pos + 1, names[i].size() - pos - 2);
int tmp_num=stoi(n2);
fre[m_find(n1)]+=tmp_num;
}
vector<string>res;
for(auto name:fre){
string tmp=to_string(name.second);
res.push_back(name.first+'('+tmp+')');
}
return res;
}
};