题目地址:
https://leetcode.com/problems/accounts-merge/
给定若干以字符串列表表示的账户,第 0 0 0个字符串是用户名,后面是其邮箱。如果两个账户share了某同一个邮箱,那么这两个账户是属于同一个人的。注意,用户名相同不意味着两个账户是属于同一个人的。要求将这些账户做合并,返回新的账户列表,第 0 0 0个字符串也是用户名,后面是其邮箱,并且要求对邮箱按字典序排序。
思路是并查集。将每个账户的所有邮箱合并在同一个集合里,然后将并查集按照祖宗节点归类,这样每一类就属于同一个用户。最后整理返回即可。代码如下:
class Solution {
public:
// 并查集的父亲数组
vector<int> p;
int idx;
// 由于我们要整理email的并查集结构,需要将email序列化为数字
unordered_map<string, int> email_to_int;
unordered_map<int, string> int_to_email;
// 存同一个用户的所有email在并查集里的根节点的序列化的值到这个用户的名字的映射
unordered_map<int, string> name_mp;
int find(int x) { return x == p[x] ? x : p[x] = find(p[x]); }
void merge(string& x, string& y) {
if (!email_to_int.count(x)) {
email_to_int[x] = idx;
int_to_email[idx++] = x;
}
if (!email_to_int.count(y)) {
email_to_int[y] = idx;
int_to_email[idx++] = y;
}
int px = find(email_to_int[x]), py = find(email_to_int[y]);
p[px] = py;
}
vector<vector<string>> accountsMerge(vector<vector<string>>& as) {
int cnt = 0;
for (auto& v : as) cnt += v.size() - 1;
p.resize(cnt);
for (int i = 0; i < p.size(); i++) p[i] = i;
for (auto& acct : as) {
auto name = acct[0];
string a1 = acct[1];
if (acct.size() == 2) merge(a1, a1);
for (int i = 2; i < acct.size(); i++) merge(acct[i], a1);
name_mp[find(email_to_int[a1])] = name;
}
unordered_map<int, set<string>> group_mp;
for (auto& acct : as) {
string a1 = acct[1];
int pp = find(email_to_int[a1]);
for (int i = 1; i < acct.size(); i++) group_mp[pp].insert(acct[i]);
}
vector<vector<string>> res;
for (auto& [k, v] : group_mp) {
vector<string> vv;
string name = name_mp[k];
vv.push_back(name);
vv.insert(vv.end(), v.begin(), v.end());
res.push_back(vv);
}
return res;
}
};
时间复杂度 O ( n l log n ) O(nl\log n) O(nllogn), n n n是字符串总数, l l l是最长字符串长度,空间 O ( n l ) O(nl) O(nl)。
844

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



