每年,政府都会公布一万个最常见的婴儿名字和它们出现的频率,也就是同名婴儿的数量。有些名字有多种拼法,例如,John 和 Jon 本质上是相同的名字,但被当成了两个名字公布出来。给定两个列表,一个是名字及对应的频率,另一个是本质相同的名字对。设计一个算法打印出每个真实名字的实际频率。注意,如果 John 和 Jon 是相同的,并且 Jon 和 Johnny 相同,则 John 与 Johnny 也相同,即它们有传递和对称性。
在结果列表中,选择字典序最小的名字作为真实名字。
添加链接描述
解题思路:
- 首先通过哈希表建立并查集,哈希表的键值对都是字符串,然后将一个相连的并查集合并;
- 利用一个哈希表进行计数,计数的时候将值都累加到根元素。
- 最后进行输出,输出的时候从头遍历,如果当前元素是一个根元素,那就输出。
注意点:
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);
}
}