Baby Names:政府每年都会公布一些最常见的婴儿名字和频率(同名婴儿的数量),其中的某些名字有多种拼法,根据婴儿名字、数量和同名表,统计每个名字实际婴儿数量。
这题的输入格式不友好,需要进行转换,具体为:
Names为编号到名字到映射Name2Idx为名字到编号的映射Synonyms为编号形式的同名表
开始时,将每个名字都视为单独的集合,即Group的下标和元素相同。然后扫描同名表Synonyms,通过更新Group中的元素实现集合的合并。
class Solution {
private:
vector<string> Names;
map<string, size_t> Name2Idx;
vector<int> Freqs;
vector<pair<size_t, size_t>> Synonyms;
vector<size_t> Group;
void addNameFreq(const string &name, const int freq)
{
Name2Idx[name] = Names.size();
Names.push_back(name);
Group.push_back(Group.size());
Freqs.push_back(freq);
}
void transformInput(const vector<string> &names, const vector<string> &synonyms)
{
for(string str : names)
{
string::size_type pos = str.find('(');
string name = str.substr(0, pos);
int freq = stoi(str.substr(pos + 1, str.size() - 2 - pos));
addNameFreq(name, freq);
}
for(string str : synonyms)
{
string::size_type pos = str.find(',');
string name1 = str.substr(1, pos - 1);
string name2 = str.substr(pos + 1, str.size() - 2 - pos);
if(Name2Idx.find(name1) == Name2Idx.end()){
addNameFreq(name1, 0);
}
if(Name2Idx.find(name2) == Name2Idx.end()){
addNameFreq(name1, 0);
}
Synonyms.push_back(make_pair(Name2Idx[name1], Name2Idx[name2]));
}
}
size_t findLeader(size_t i)
{
if(Group[i] == i) return i;
else return findLeader(Group[i]);
}
void groupName()
{
for(auto p : Synonyms)
{
size_t Leader1Idx = findLeader(p.first);
size_t Leader2Idx = findLeader(p.second);
if(Names[Leader1Idx] < Names[Leader2Idx]) Group[Leader2Idx] = Leader1Idx;
else Group[Leader1Idx] = Leader2Idx;
}
}
vector<string> transformOutput()
{
vector<string> result;
map<string, int> Popular;
for(size_t i = 0; i < Names.size(); i++)
{
size_t LeaderIdx = findLeader(i);
Popular[Names[LeaderIdx]] += Freqs[i];
}
for(auto iter = Popular.begin(); iter != Popular.end(); iter++)
{
result.push_back(iter->first);
result.back().push_back('(');
result.back().append(to_string(iter->second));
result.back().push_back(')');
}
return result;
}
public:
vector<string> trulyMostPopular(vector<string> &names, vector<string> &synonyms) {
transformInput(names, synonyms);
groupName();
return transformOutput();
}
};
除了并查集的方法,也可以通过划分连通子图求解,思路应该是没问题的,但是交上去后超时了。
class Solution {
private:
vector<string> Names;
map<string, size_t> Name2Idx;
vector<int> Freqs;
vector<vector<bool>> Graph;
map<string, int> Popular;
void addNameFreq(const string &name, const int freq)
{
Name2Idx[name] = Names.size();
Names.push_back(name);
Freqs.push_back(freq);
}
void transformInput(const vector<string> &names, const vector<string> &synonyms)
{
for(string str : names)
{
string::size_type pos = str.find('(');
string name = str.substr(0, pos);
int freq = stoi(str.substr(pos + 1, str.size() - 2 - pos));
addNameFreq(name, freq);
}
vector<pair<size_t, size_t>> Synonyms;
for(string str : synonyms)
{
string::size_type pos = str.find(',');
string name1 = str.substr(1, pos - 1);
string name2 = str.substr(pos + 1, str.size() - 2 - pos);
if(Name2Idx.find(name1) == Name2Idx.end()){
addNameFreq(name1, 0);
}
if(Name2Idx.find(name2) == Name2Idx.end()){
addNameFreq(name1, 0);
}
Synonyms.push_back(make_pair(Name2Idx[name1], Name2Idx[name2]));
}
Graph.assign(Names.size(), vector<bool>(Names.size(), false));
for(auto p : Synonyms)
{
Graph[p.first][p.second] = Graph[p.second][p.first] = true;
}
}
void groupName()
{
vector<bool> Visited(Names.size(), false);
for(size_t i = 0; i < Names.size(); i++)
{
if(!Visited[i]){
int TotalFreq = 0;
string LessName(Names[i]);
queue<size_t> group;
group.push(i);
Visited[i] = true;
while(!group.empty()){
size_t FrontIdx = group.front();
group.pop();
if(Names[FrontIdx] < LessName) LessName = Names[FrontIdx];
TotalFreq += Freqs[FrontIdx];
for(size_t adj = 0; adj < Names.size(); adj++)
{
if(Graph[FrontIdx][adj] && !Visited[adj]){
group.push(adj);
Visited[adj] = true;
}
}
}
Popular[LessName] = TotalFreq;
}
}
}
vector<string> transformOutput()
{
vector<string> result;
for(auto iter = Popular.begin(); iter != Popular.end(); iter++)
{
result.push_back(iter->first);
result.back().push_back('(');
result.back().append(to_string(iter->second));
result.back().push_back(')');
}
return result;
}
public:
vector<string> trulyMostPopular(vector<string> &names, vector<string> &synonyms) {
transformInput(names, synonyms);
groupName();
return transformOutput();
}
};
本文介绍了一种算法,用于处理BabyNames数据集中的婴儿名字统计问题。该算法首先将输入数据转换为更易于处理的格式,然后使用并查集或连通子图方法来合并具有多种拼写方式的同名集合,最终输出每个名字的实际婴儿数量。

被折叠的 条评论
为什么被折叠?



