这道题目比较有难度,名字允许相同,对应不同的邮箱,邮箱相同一定对应同一个账户,一个账户可能有多个邮箱,
所以如何标记一个账户?直接用编号id
首先我们使用一个HashMap,从邮箱映射到id,一旦发现有相同的邮箱时,就用并查集把id连起来,并查集维护的是id。
但是答案,要求的是id对应邮箱,因此我们需要在建立一个hashmap,里面是id,对应邮箱集合。
我们遍历之前的map,找到邮箱和id,通过并查集将id对应到根节点的id。
然后得到id,邮箱集合数组,由于通过遍历hashmap得到,所以邮箱数组一定不会有重复。
最后,我们再遍历一次id,邮箱数组,然后将数据加入答案数组,这题总体逻辑比较绕,面试中第一次见难度很大。
class Union{
private:
vector<int> p;
int n;
public:
Union(){}
Union(int n){
this->n = n;
p.resize(n);
for(int i=0;i<n;i++){
p[i] = i;
}
}
int find(int x){
if(x!=p[x]) p[x] = find(p[x]);
return p[x];
}
void unite(int x,int y){
p[find(x)] = find(y);
}
bool isUnite(int x, int y){
return p[x] == p[y];
}
};
const int N = 2000;
class Solution {
public:
vector<vector<string>> accountsMerge(vector<vector<string>>& accounts) {
vector<vector<string>> res;
unordered_map<string,int> emailToIndex; // 用邮箱对应编号,将相同的邮箱连起来
int n = accounts.size();
Union un(n);
for(int i=0;i<n;i++){
for(int j=1;j<accounts[i].size();j++){
if(emailToIndex.count(accounts[i][j])){
un.unite(emailToIndex[accounts[i][j]],i);
}else{
emailToIndex[accounts[i][j]] = i;
}
}
}
// 邮箱Id对应账号,只需返过来遍历HashMap
unordered_map<int,vector<string>> indexToEmail;
for(auto &[email,index]:emailToIndex){
indexToEmail[un.find(index)].push_back(email);
}
for(auto &[index,emails]:indexToEmail){
sort(emails.begin(),emails.end());
vector<string> tmp;
tmp.push_back(accounts[index][0]);
for(auto email:emails){
tmp.push_back(email);
}
res.push_back(tmp);
}
return res;
}
};