并查集

并查集详解(超级简单有趣~~就学会了)
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;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值