并查集之面试题 17.07. 婴儿名字
前言
并查集
一, 面试题 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
二,解题思路
1, a和b是朋友, b和c是朋友,那a和c也是朋友。这就是典型并查集类型
所以这个题目是并查集类型的题目
2, 字典序
比较玩家的姓名
3,
三, 代码
#include <unordered_map>
#include <iostream>
#include <vector>
using namespace std;
#include <iostream>
#include <vector>
class Solution {
private:
struct name_size
{
std::string name;
int size;
};
private:
int getfriend(int * unoin_find, int v)
{
if (unoin_find[v] == v)
{
return v;
}
return unoin_find[v] = getfriend(&unoin_find[0], unoin_find[v]);
}
public:
void init(int *unoin_find, int size)
{
for (int i = 0; i < size; ++i)
{
unoin_find[i] = i;
}
}
/**
* 返回字典序最小的字符串
* @param name1
* @param name2
* @return
*/
std::string checkout_trie(std::string name1, std::string name2)
{
if (name1.size() >= name2.size())
{
for (int i = 0; i < name2.size(); ++i)
{
if (name1[i] < name2[i])
{
return name1;
}
else if (name1[i] > name2[i])
{
return name2;
}
}
return name2;
}
else
{
for (int i = 0; i < name1.size(); ++i)
{
if (name1[i] < name2[i])
{
return name1;
}
else if (name1[i] > name2[i])
{
return name2;
}
}
return name1;
}
return name1;
}
vector<string> trulyMostPopular(vector<string>& names, vector<string>& synonyms)
{
std::unordered_map<std::string, int> m_name_index;
int unoin_find[names.size()+1];
init(&unoin_find[0], names.size() +1);
for (int j = 0; j < names.size(); ++j)
{
std::string name ;
std::string num ;
bool name_num = false;
int name_index = 0;
for (int i = 0; i < names[j].size(); ++i)
{
if (names[j][i] == '(')
{
name.append(names[j], 0, i);
name_index = i;
name_num = true;
}
if (name_num)
{
if (names[j][i] == '(' || names[j][i] == ')')
{}
else
{
num.append(names[j], name_index+1, names[j].size());
num.erase(std::remove(num.begin(), num.end(), ')'), num.end());
break;
}
}
}
m_name_map[j].name = name;
m_name_map[j].size = atoi(num.c_str()) ;
m_name_index[name] = j;
}
for (int j = 0; j < synonyms.size(); ++j)
{
std::string name1 ;
std::string name2;
int name1_index = 0;
bool name_num = false;
for (int i = 2; i < synonyms[j].size(); ++i)
{
if (name1_index == 0 && synonyms[j][i] == ',')
{
name1_index = i;
name1.append(synonyms[j], 1, i-1);
}
if (name1_index> 0)
{
if (synonyms[j][i] == ',' || synonyms[j][i] == ')')
{}
else
{
name2.append(synonyms[j], name1_index+1, synonyms[j].size());
name2.erase(std::remove(name2.begin(), name2.end(), ')'), name2.end());
break;
}
}
}
int v1;
{
auto iter = m_name_index.find(name1);
if (iter == m_name_index.end())
{
continue;
}
v1 = getfriend(&unoin_find[0], m_name_index[name1]);
}
int v2;
{
auto iter = m_name_index.find(name2);
if (iter == m_name_index.end())
{
continue;
}
v2 = getfriend(&unoin_find[0], m_name_index[name2]);
}
if (v1 < v2)
{
unoin_find[m_name_index[name2]] = v1;
for (int w = 0; w < names.size(); ++w)
{
if (unoin_find[w] == v2)
{
unoin_find[w] = v1;
}
}
}
else if (v1 > v2)
{
unoin_find[m_name_index[name1]] = v1;
for (int w = 0; w < names.size(); ++w)
{
if (unoin_find[w] == v1)
{
unoin_find[w] = v2;
}
}
}
}
std::vector<name_size> ret(names.size());
for (int i = 0; i < names.size(); ++i)
{
ret[unoin_find[i]].size += m_name_map[i].size;
if (ret[unoin_find[i]].name.size() <1)
{
ret[unoin_find[i]].name = m_name_map[i].name;
}
else
{
ret[unoin_find[i]].name = checkout_trie(ret[unoin_find[i]].name, m_name_map[i].name);
}
}
std::vector<std::string> new_ret;
for (const name_size& value: ret )
{
if (value.size > 0)
{
std::string new_name = value.name;
new_name.append("(");
new_name.append(std::to_string(value.size));
new_name.append(")");
new_ret.push_back(new_name);
}
}
return new_ret;
}
std::unordered_map<int, name_size> m_name_map;
};
时间复杂度O()
空间复杂度O()