题目来源
题目描述
class Solution {
public:
vector<vector<string>> accountsMerge(vector<vector<string>>& accounts) {
}
};
题目解析
题意:给出一堆账户和对应的邮箱。要求合并同一个人的多个邮箱账户。
并查集
由题意知道:
- 存在相同邮箱的账号一定是同一个人
- 名称相同的账户不一定是同一个人。
所以我们只能通过邮箱是否相同来判断是否是同一个人。
思路:
- 先初始化每个账户为1个连通分量
- 遍历每个账户下的邮箱,判断该邮箱是否在其他账户下出现
- 如果未出现,继续
- 如果账户A、B下出现了相同的邮箱email,那么将账户A和账户B两个连通分量进行合并
- 最后遍历并查集中每个连通分量,将所有连通分量内部账户的邮箱全部合并(相同的去重,不同的合并)
class Solution {
class UnionFind{
private:
std::vector<int> parent; // parent[i] = k : i的父亲是k
std::vector<int> size; // size[i] = k : 如果i是代表节点,size[i]才有意义( i所在的集合大小是多少),否则无意义
std::vector<int> help; // 辅助结构
int cnt; //一共有多少个集合
public:
explicit UnionFind(int n){
cnt = n;
parent.resize(n);
size.resize(n);
help.resize(n);
for (int i = 0; i < n; ++i) {
parent[i] = i;
size[i] = 1;
}
}
// 返回i的代表节点
// 这个过程要做路径压缩
int findRoot(int i){
int hi = 0;
while (i != parent[i]){
help[hi++] = parent[i];
i = parent[i];
}
for (hi--; hi >= 0; --hi) {
parent[help[hi]] = i;
}
return i;
}
void merge(int i, int j){
int f1 = findRoot(i);
int f2 = findRoot(j);
if(f1 != f2){
if(size[f1] >= size[f2]){
parent[f2] = f1;
size[f1] = size[f1] + size[f2];
}else{
parent[f1] = f2;
size[f2] = size[f2] + size[f1];
}
--cnt;
}
}
int counts() const{
return cnt;
}
};
public:
vector<vector<string>> accountsMerge(vector<vector<string>>& accounts) {
vector<vector<string>> res;
// 作用:存储每个邮箱属于哪个账户 ,同时 在遍历邮箱时,判断邮箱是否出现过
// 格式:<邮箱,账户id>
std::unordered_map<std::string, int> mapEA;
int n = accounts.size();
UnionFind uf(n);
for (int i = 0; i < n; ++i) {
int m = accounts[i].size();
for (int j = 1; j < m; ++j) {
string s = accounts[i][j];
if(mapEA.find(s) == mapEA.end()){
mapEA[s] = i;
}else{
uf.merge(i, mapEA[s]);
}
}
}
// 作用: 存储每个账户下的邮箱
// 格式: <账户id, 邮箱列表> >
// 注意:这里的key必须是账户id,不能是账户名称,名称可能相同,会造成覆盖
std::unordered_map<int, std::vector<std::string>> mapAEs;
for(auto &it : mapEA){ // <邮箱,账户id>
auto id = uf.findRoot(it.second);
mapAEs[id].emplace_back(it.first);
}
for(auto &it : mapAEs){
auto emails = it.second;
auto id = it.first;
std::sort(emails.begin(), emails.end());
std::vector<std::string> tmp(1, accounts[id][0]);
tmp.insert(tmp.end(), emails.begin(), emails.end());
res.emplace_back(tmp);
}
return res;
}
};