题目
每年,政府都会公布一万个最常见的婴儿名字和它们出现的频率,也就是同名婴儿的数量。有些名字有多种拼法,例如,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)”]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/baby-names-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
使用并查集求解,将names
中的每个婴儿名字作为并查集的元素,通过遍历synonyms
合并相同的婴儿名字,即确定元素间的父子关系,在合并时(即union函数),首先找到两个婴儿名字的祖宗,并将祖宗名字小的作为新的祖宗(题目要求选择字典序最小的名字作为真实名字)。
确定父子关系后,统计婴儿名字的频率,统计时先找到该名字的祖宗,然后将该名字的频率叠加到祖宗名字的频率上。
class UnionFindSet {
int parent[];
public UnionFindSet(int n) {
parent = new int[n];
for (int i = 0; i < n; i++)
parent[i] = -1;
}
public int find(int i) {
if (parent[i] < 0)
return i;
parent[i] = find(parent[i]);
return parent[i];
}
public void union(int i, int j, Map<Integer, String> nameIdx) {
// 合并i和j, 并且让i j中祖宗的字典序最小的作为父亲, 并返回父亲坐标
int ii = find(i);
int jj = find(j);
String nameii = nameIdx.get(ii);
String namejj = nameIdx.get(jj);
if (ii != jj) {
if (nameii.compareTo(namejj) < 0)
// nameii < namejj, let ii be the father.
parent[jj] = ii;
else
parent[ii] = jj;
}
}
}
class Solution {
public String[] trulyMostPopular(String[] names, String[] synonyms) {
/**
* 输入:names = ["John(15)","Jon(12)","Chris(13)","Kris(4)","Christopher(19)"],
* synonyms = ["(Jon,John)","(John,Johnny)","(Chris,Kris)","(Kris,Christopher)"]
* 输出:["John(27)","Chris(36)"]
*/
int n = names.length;
UnionFindSet ufset = new UnionFindSet(n);
Map<String, Integer> nameIndexMap = new HashMap();
Map<Integer, String> indexnameMap = new HashMap();
for (int i = 0; i < n; i++) {
// get name
int idx1 = names[i].indexOf('(');
int idx2 = names[i].indexOf(')');
String name = names[i].substring(0, idx1);
nameIndexMap.put(name, i);
indexnameMap.put(i, name);
}
for (String pair : synonyms) {
int idx1 = pair.indexOf('(');
int idx2 = pair.indexOf(',');
int idx3 = pair.indexOf(')');
String name1 = pair.substring(idx1 + 1, idx2);
String name2 = pair.substring(idx2 + 1, idx3);
if (nameIndexMap.containsKey(name1) && nameIndexMap.containsKey(name2)) {
int id1 = nameIndexMap.get(name1), id2 = nameIndexMap.get(name2);
ufset.union(id1, id2, indexnameMap);
}
}
Map<String, Integer> nameFreqMap = new HashMap<>();
for (int i = 0; i < n; i++) {
int f = ufset.find(i);
// get frequency of name i.
int freqi = Integer.valueOf(names[i].substring(names[i].indexOf('(') + 1, names[i].indexOf(')')));
String namef = names[f].substring(0, names[f].indexOf('('));
if (nameFreqMap.containsKey(namef)) {
int count = nameFreqMap.get(namef) + freqi;
nameFreqMap.remove(namef);
nameFreqMap.put(namef, count);
} else {
nameFreqMap.put(namef, freqi);
}
}
String res[] = new String[nameFreqMap.size()];
int i = 0;
for (String key : nameFreqMap.keySet()) {
String tmp = key + '(' + nameFreqMap.get(key).toString() + ')';
res[i] = tmp;
i++;
}
return res;
}
}
这里主要用到字符串的indexOf
,substring
等操作