ToB企服应用市场:ToB评测及商务社交产业平台
标题:
机试题——通讯录归并
[打印本页]
作者:
九天猎人
时间:
昨天 19:58
标题:
机试题——通讯录归并
题目描述
你有一个通讯录,每个联系人包含姓名和手机号,一个联系人大概有多个手机号。假如两个联系人拥有相同的手机号,我们以为他们是同一个人。任务是整理通讯录,将具有相同手机号的联系人归并为一个联系人,并返回归并后的通讯录列表。假如归并时发现联系人姓名差别,以字典序小的为姓名。
输入描述
第一行:一个整数num,表示通讯录的记录数量(1 <= num <= 1000)。
接下来num行:每行表示一条联系人记录,包含姓名和多少电话号码(电话号码个数不超过10,长度在1到10之间)。姓名由英文字母大小写构成,长度在1到10之间。
输出描述
整理后的通讯录列表,此中具有相同手机号的联系人归并为一个联系人。输出联系人姓名和手机号码列表按ASCII码升序排序。
用例输入
4
kaka 10000000000 10000000001
tata 10000000020
kaka 10000000000 10000000002
tata 10000000010
复制代码
kaka 10000000000 10000000001 10000000002
tata 10000000010
tata 10000000020
复制代码
第一个kaka和第二个kaka有相同的手机号10000000000,因此他们被视为同一个人。归并后的手机号按ASCII码升序排序。
3
kaka 10000000000 10000000001
kaka 10000000001 10000000002
kaka 10000000002 10000000003
复制代码
kaka 10000000000 10000000001 10000000002 10000000003
复制代码
第一个kaka和第二个kaka有相同的手机号10000000001,第二个kaka和第三个kaka有相同的手机号10000000002,因此他们被视为同一个人。归并后的手机号按ASCII码升序排序。
解题思路
题目建模
:
使用
并查集
来归并具有相同手机号的联系人。
使用
哈希表
记录每个手机号对应的联系人索引。
使用
集合
去重并排序手机号。
并查集
:
对于每个联系人的手机号,假如该手机号已经出现过,则将当前联系人与之前出现的联系人归并。
使用路径压缩优化并查集。
归并联系人
:
对于每个联系人,找到其根节点(即归并后的代表)。
归并手机号,去重并排序。
假如姓名差别,选择字典序小的姓名。
输出结果
:
按姓名和手机号的ASCII码升序排序,输出归并后的通讯录。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<algorithm>
#include<string>
#include<vector>
#include<unordered_map>
#include<unordered_set>
#include<queue>
#include<set>
#include<list>
#include<sstream>
#include<bitset>
#include<stack>
#include<climits>
#include<iomanip>
#include<cstdint>
using namespace std;
// 并查集
vector<int> f(10005);
int find(int x) {
if (f[x] == x) return x;
else return f[x] = find(f[x]);
}
void un(int x, int y) {
int fx = find(x);
f[fx] = y;
}
int main() {
ios::sync_with_stdio(false); // 关闭与 C 的同步
cin.tie(nullptr); // 解除 cin 与 cout 的绑定
int n;
cin >> n;
cin.ignore();
vector<string> name(n);
vector<vector<string>> phone(n);
map<string, int> memo; // 记录手机号对应的联系人索引
for (int i = 0; i < n; i++) {
f[i] = i; // 初始化并查集
string input, temp;
getline(cin, input);
istringstream is(input);
is >> name[i];
while (is >> temp) {
if (memo.count(temp)) { // 如果手机号已经出现过
un(memo[temp], i); // 合并两个联系人
}
memo[temp] = i; // 更新手机号对应的联系人索引
phone[i].push_back(temp); // 记录当前联系人的手机号
}
}
// 开始合并
map<int, vector<int>> unio; // 父节点和其子集
map<string, vector<vector<string>>> res; // 一个名字可能对应多个通讯录号
for (int i = 0; i < n; i++) {
int cf = find(i); // 找到当前联系人的根节点
unio[cf].push_back(i); // 合并到同一个集合
}
// 排序并输出结果
for (auto& f : unio) {
string cur_name;
set<string> cur_phone; // 去重并排序手机号
for (int c : f.second) {
// 查询当前集合的名字最小值
if (cur_name.size() == 0)
cur_name = name[c];
else
cur_name = min(cur_name, name[c]);
// 合并当前联系人的所有手机号
for (int i = 0; i < phone[c].size(); i++) {
cur_phone.insert(phone[c][i]);
}
}
vector<string> v_phone(cur_phone.begin(), cur_phone.end());
res[cur_name].push_back(v_phone); // 保存结果
}
// 按姓名和手机号的ASCII码升序排序
for (auto& t : res) {
sort(t.second.begin(), t.second.end());
for (auto c : t.second) {
cout << t.first;
for (int i = 0; i < c.size(); i++)
cout << " " << c[i];
cout << "\n";
}
}
return 0;
}
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/)
Powered by Discuz! X3.4