leetcode面试题 17.07. 婴儿名字(并查集)

每年,政府都会公布一万个最常见的婴儿名字和它们出现的频率,也就是同名婴儿的数量。有些名字有多种拼法,例如,John 和 Jon 本质上是相同的名字,但被当成了两个名字公布出来。给定两个列表,一个是名字及对应的频率,另一个是本质相同的名字对。设计一个算法打印出每个真实名字的实际频率。注意,如果 John 和 Jon 是相同的,并且 Jon 和 Johnny 相同,则 John 与 Johnny 也相同,即它们有传递和对称性。

在结果列表中,选择字典序最小的名字作为真实名字。

示例:

输入:names = [“John(15)”,“Jon(12)”,“Chris(13)”,“Kris(4)”,“Christopher(19)”], synonyms = ["(Jon,John)","(John,Johnny)","(Chris,Kris)","(Chris,Christopher)"]
输出:[“John(27)”,“Chris(36)”]

代码

class Solution {
    int[] strFa;
    public void  strInit()//并查集操作
    {
        for(int i=0;i<strFa.length;i++)
            strFa[i]=i;

    }
    public int  strFind(int x)
    {
        if(x!=strFa[x])
            strFa[x]=strFind(strFa[x]);
        return strFa[x];
    }
    public void   strUnion(int x,int y)
    {
        x=strFind(x);
        y=strFind(y);
        if(x==y) return;
        if(map.get(y).compareTo(map.get(strFa[x]))<0)//按字典序确定父节点
            strFa[x]=y;
        else strFa[y]=x;
    }  Map<Integer,String>map=new HashMap<>();
    public String[] trulyMostPopular(String[] names, String[] synonyms) {

        int n=names.length;
        strFa=new int[n];
        strInit();
        Map<String,Integer>map2=new HashMap<>(); int[] res=new int[n];
        for(int i=0;i<n;i++)//将名字和对应的编号用map记录
        {
            String[] name=names[i].split("[()]");
            map.put(i,name[0]);
            map2.put(name[0],i);
            res[i]=Integer.parseInt(name[1]);
        }
        List<String> list=new ArrayList<>();
        for(String s:synonyms)//构建并查集
        {
             String name1=s.substring(1,s.indexOf(','));
            String name2=s.substring(s.indexOf(',')+1,s.length()-1);
             if(map2.containsKey(name1)&&map2.containsKey(name2))
            strUnion(map2.get(name1),map2.get(name2));
          
        }
     
         for(int i=0;i<n;i++)//将子节点的值累加到父节点
        {
            if(strFa[i]!=i) res[strFind(i)]+=res[i];
        }
        for(int i=0;i<n;i++)//返回所有的不相交的父节点
            if(strFa[i]==i){
                 list.add(map.get(i)+'('+res[i]+')');
            }
        String[] ret=new String[list.size()];
            for(int i=0;i<list.size();i++)
                ret[i]=list.get(i);
           return ret;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值