• 算法——婴儿名字


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

    解题思路:

    1. 首先通过哈希表建立并查集,哈希表的键值对都是字符串,然后将一个相连的并查集合并;
    2. 利用一个哈希表进行计数,计数的时候将值都累加到根元素。
    3. 最后进行输出,输出的时候从头遍历,如果当前元素是一个根元素,那就输出。

    注意点:
    1.在合并的时候,为了满足题意,将字典序小的根元素作为新的根元素。

    这里用到的并查集的模板进行编写程序。一般并查集都是利用数字最为元素标识,模板操作如下:

    List<Integer> p = new ArrayList<>();
    // 查找根
    public int find(int x){
        if(p.get(x) != x){
            p.set(x, find(p.get(x)));
        }
        return p.get(x);
    }
    
    //合并
    p.set(find(a), find(b));
    

    其实,不只是数字,只要是可以产生映射的元素都是可以用并查集来实现的。本题,就是通过哈希表将字符串进行映射,构造并查集。

    题目代码:

    class Solution {
        Map<String, String> map;
        public String[] trulyMostPopular(String[] names, String[] synonyms) {
            Map<String, Integer> cnt = new HashMap<>();
            map = new HashMap<>();
    
            for(String name : names) {
                int i = 0;
                while(name.charAt(i) != '(') i++;
                map.put(name.substring(0, i), name.substring(0, i));
            }  
    
            for(String name : synonyms) {
                String[] temp = name.split(",");
                String x = temp[0].substring(1, temp[0].length());
                String y = temp[1].substring(0, temp[1].length() - 1);
    
                if(!map.containsKey(x)) map.put(x, x);
                if(!map.containsKey(y)) map.put(y, y);
    
                // 获得两个集合的根
                String fx = find(x);
                String fy = find(y);
    
                // 合并两个并查集,将字典序小的根作为新的根
                if(!fx.equals(fy)){
                    if(fx.compareTo(fy) > 0) map.put(fx, fy);
                    else map.put(fy, fx);
                }
            }
    
            for(String name : names) {
                int i = 0;
                while(name.charAt(i) != '(') i++;
    
                // 将数值都累加到根的位置
                String root = find(name.substring(0, i));
                cnt.put(root, cnt.getOrDefault(root, 0) + Integer.parseInt(name.substring(i + 1, name.length() - 1)));
            }
    
            List<String> res = new ArrayList<>();
    
            for(String name : names) {
                int i = 0;
                while(name.charAt(i) != '(') i++;
    
                String root = find(name.substring(0, i));
                
                // 只输出根
                if(!root.equals(name.substring(0, i))) continue;
    
                res.add(root + "(" + String.valueOf(cnt.get(root)) + ")");
            }
    
            return res.toArray(new String[res.size()]);
        }
    
        // 查根
        public String find(String x) {
            if(!map.get(x).equals(x)) {
                map.put(x, find(map.get(x)));
            }
    
            return map.get(x);
        }
    }
    
  • 相关阅读:
    bzoj1711: [Usaco2007 Open]Dining吃饭
    bzoj1036: [ZJOI2008]树的统计Count
    bzoj1497: [NOI2006]最大获利
    bzoj2561: 最小生成树
    BZOJ 2083: [Poi2010]Intelligence test( )
    BZOJ 2212: [Poi2011]Tree Rotations( 线段树 )
    BZOJ 1110: [POI2007]砝码Odw( 贪心 )
    BZOJ 3163: [Heoi2013]Eden的新背包问题( 背包dp )
    BZOJ 1537: [POI2005]Aut- The Bus(dp + BIT)
    BZOJ 2875: [Noi2012]随机数生成器( 矩阵快速幂 )
  • 原文地址:https://www.cnblogs.com/lippon/p/14117634.html
Copyright © 2020-2023  润新知