程序员面试金典 17.7

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();
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值