题目:
每年,*都会公布一万个最常见的婴儿名字和它们出现的频率,也就是同名婴儿的数量。有些名字有多种拼法,例如,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
答案:
class Solution {
public String[] trulyMostPopular(String[] names, String[] synonyms) {
//用hashmap表存频率,字典序就是按顺序一次比较每个字符大小
Map<String, Integer> map = new HashMap<>();
Map<String, String> nmap = new HashMap<>();
//统计频率
for(String name : names){
int index1 = name.indexOf('('), index2 = name.indexOf(')');
map.put(name.substring(0, index1), Integer.parseInt(name.substring(index1 + 1, index2)));
//System.out.println(name.substring(0, index1) + " " + Integer.parseInt(name.substring(index1 + 1, index2)));
}
//字典序小的在后,大的都在前
for(String name : synonyms){
int index = name.indexOf(','), i = 0;
String str1 = name.substring(1, index), str2 = name.substring(index + 1, name.length() - 1);
while (nmap.containsKey(str1)) { //找str1祖宗
str1 = nmap.get(str1);
}
while (nmap.containsKey(str2)) { //找str2祖宗
str2 = nmap.get(str2);
}
if(!str1.equals(str2)){ //祖宗不同,要合并
int frequency = map.getOrDefault(str1, 0) + map.getOrDefault(str2, 0); //出现次数是两者之和
String trulyName = str1.compareTo(str2) < 0 ? str1 : str2;
String nickName = str1.compareTo(str2) < 0 ? str2 : str1;
nmap.put(nickName, trulyName); //小名作为大名的分支,即大名是小名的祖宗
map.remove(nickName); //更新一下数据
map.put(trulyName, frequency);
}
}
int i = 0;
String[] strs = new String[map.size()];
for(String name : map.keySet()){
StringBuffer sb = new StringBuffer(name);
sb.append("(");
sb.append(map.get(name));
sb.append(")");
strs[i++] = sb.toString();
}
return strs;
}
}