面试题 17.07. 婴儿名字

面试题 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)"]
 

提示:

names.length <= 100000

方法1:并查集

public String[] trulyMostPopular(String[] names, String[] synonyms) {
    UnionFind uf = new UnionFind();
    for (String name : names) {
        String x = name.substring(0, name.indexOf("("));
        Integer cnt = Integer.valueOf(name.substring(name.indexOf("(") + 1, name.indexOf(")")));
        uf.parents.put(x, x);
        uf.size.put(x, cnt);
    }

    for (String syn : synonyms) {
        String u = syn.substring(1, syn.indexOf(","));
        String v = syn.substring(syn.indexOf(",") + 1, syn.indexOf(")"));
        if (!uf.parents.containsKey(u)) {//需要处理不存在的,并初始化size
            uf.parents.put(u, u);
            uf.size.put(u, 0);
        }
        if (!uf.parents.containsKey(v)) {
            uf.parents.put(v, v);
            uf.size.put(v, 0);
        }
        uf.union(u, v);
    }
    List<String> res = new ArrayList<>();
    for (String name : names) {
        String x = name.substring(0, name.indexOf("("));
        String rootX = uf.find(x);
        if (x.equals(rootX)) {
            res.add(x + "(" + uf.getSize(x) + ")");
        }
    }
    return res.toArray(new String[res.size()]);
}

class UnionFind {

    Map<String, String> parents;//当前节点的父节点
    Map<String, Integer> size;//当前节点的人数


    public UnionFind() {
        parents = new HashMap<>();
        size = new HashMap<>();
    }

    //找到x的根节点
    public String find(String x) {
        if (!x.equals(parents.get(x))) {
            parents.put(x, find(parents.get(x)));
        }
        return parents.get(x);
    }

    public boolean union(String x, String y) {
        String rootX = find(x), rootY = find(y);
        if (rootX.equals(rootY)) return false;
        //字典序小的做根
        if (rootX.compareTo(rootY) > 0) {//rootY的字典序小
            parents.put(rootX, rootY);
            size.put(rootY, size.get(rootX) + size.get(rootY));
        } else {
            parents.put(rootY, rootX);
            size.put(rootX, size.get(rootY) + size.get(rootX));
        }
        return true;
    }

    /**
     * 返回x对应的根节点包含的人数
     */
    public int getSize(String x) {
        String rootX = find(x);
        return size.get(rootX);
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值