面试题 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
代码:
class Solution {
public:
unordered_map<string,int> name_freq;
unordered_map<string,string> pre;
string find(string root)
{
string son,tmp;
son=root;
while(root!=pre[root]) //找到父节点
root=pre[root];
while(son!=root) //路径压缩
{
tmp=pre[son];
pre[son]=root;
son=tmp;
}
return root;
}
void join(string r1, string r2)
{
if(pre.find(r1)==pre.end() || pre.find(r2)==pre.end())
return;
string p1=find(r1);
string p2=find(r2);
if(p1!=p2)
{
if(p1<p2)
{
pre[p2]=p1;
int tmp_freq=name_freq[p2];
name_freq.erase(p2);
name_freq[p1]+=tmp_freq;
}else{
pre[p1]=p2;
int tmp_freq=name_freq[p1];
name_freq.erase(p1);
name_freq[p2]+=tmp_freq;
}
}
}
vector<string> trulyMostPopular(vector<string>& names, vector<string>& synonyms)
{
for (auto c : names)
{
int ind = c.find('(');
string tmp_name = c.substr(0, ind);
int tmp_freq = stoi(c.substr(ind + 1, c.length() - ind - 2));
name_freq[tmp_name] = tmp_freq;
pre[tmp_name] = tmp_name;
}
for (auto c : synonyms)
{
int ind = c.find(',');
string tmp_name1 = c.substr(1, ind - 1);
string tmp_name2 = c.substr(ind + 1, c.length() - ind - 2);
join(tmp_name1, tmp_name2);
}
vector<string> res;
for (auto it = name_freq.begin(); it != name_freq.end(); it++)
{
string tmp_res = it->first + "(" + to_string(it->second) + ")";
res.push_back(tmp_res);
}
return res;
}
};