Given a list accounts
, each element accounts[i]
is a list of strings, where the first element accounts[i][0]
is a name, and the rest of the elements are emails representing emails of the account.
Now, we would like to merge these accounts. Two accounts definitely belong to the same person if there is some email that is common to both accounts. Note that even if two accounts have the same name, they may belong to different people as people could have the same name. A person can have any number of accounts initially, but all of their accounts definitely have the same name.
After merging the accounts, return the accounts in the following format: the first element of each account is the name, and the rest of the elements are emails in sorted order. The accounts themselves can be returned in any order.
Example 1:
Input: accounts = [["John", "johnsmith@mail.com", "john00@mail.com"], ["John", "johnnybravo@mail.com"], ["John", "johnsmith@mail.com", "john_newyork@mail.com"], ["Mary", "mary@mail.com"]] Output: [["John", 'john00@mail.com', 'john_newyork@mail.com', 'johnsmith@mail.com'], ["John", "johnnybravo@mail.com"], ["Mary", "mary@mail.com"]] Explanation: The first and third John's are the same person as they have the common email "johnsmith@mail.com". The second John and Mary are different people as none of their email addresses are used by other accounts. We could return these lists in any order, for example the answer [['Mary', 'mary@mail.com'], ['John', 'johnnybravo@mail.com'], ['John', 'john00@mail.com', 'john_newyork@mail.com', 'johnsmith@mail.com']] would still be accepted.
解题思路:由于邮件名字唯一、人名不唯一,我们将每个不重复邮件地址映射为一个单独的id。
映射时,要将id对应的人名记录下来。
映射后,每个accounts[i]下的每个邮件地址(包括与之前重复的和新出现的)都会有一个自己的id,因为这些邮件id的属于同一个人,所以要将这些id连通
最后,通过将所有对应的根id相同的邮件名字和对应的那个人名放在一起构成一个vector,将根id映射成这个vector
注意,输出最后结果时,每个vector要排序。
连通(UINION)时,通过FIND找到两个id各自的根id,判断哪个根id下所包含的结点少,将少的那个“根id”的父id设为大的那个根id。
查找(FIND)时,只有根id的父id会是自己,所以用一个循环不断地往前推直到找到父id是自己id的点。并且在这个过程中,进行路径压缩,将当亲结点的父id赋值为它父亲的父id。
class Solution {
public:
int FIND(int p, vector<int>& id) {
while (p != id[p]) {
id[p] = id[id[p]];
p = id[p];
}
return p;
}
void UNION(int p, int q, vector<int>& id, vector<int>& sz) {
int i = FIND(p,id);
int j = FIND(q,id);
if (i == j) return;
if (sz[i] < sz[j]) {
id[i] = j;
sz[j] += sz[i];
} else {
id[j] = i;
sz[i] += sz[j];
}
}
vector<vector<string>> accountsMerge(vector<vector<string>>& accounts) {
// map different email addresses to integers
map<string,int> email2int;
vector<string> owner;
vector<int> mp;
vector<int> sz;
int id = -1;
for (int i = 0; i < accounts.size(); i++) {
string name = accounts[i][0];
for (int j = 1; j < accounts[i].size(); j++) {
if (email2int.find(accounts[i][j]) == email2int.end()) {
email2int.insert(make_pair(accounts[i][j],++id));
owner.push_back(name);
mp.push_back(id);
sz.push_back(1);
}
}
int first = email2int[accounts[i][1]];
for (int j = 2; j < accounts[i].size(); j++) {
int tmp = email2int[accounts[i][j]];
UNION(first, tmp, mp, sz);
}
}
map<int, vector<string>> res;
map<string,int>::iterator iter;
for (iter = email2int.begin(); iter != email2int.end(); iter++) {
int tmp = FIND(mp[iter->second],mp);
if (res.find(tmp) == res.end()) {
vector<string> s;
s.push_back(owner[tmp]);
s.push_back((*iter).first);
res.insert(make_pair(tmp,s));
} else {
res[tmp].push_back((*iter).first);
}
}
vector<vector<string>> ans(res.size());
int index = 0;
map<int,vector<string>>::iterator it;
for (it = res.begin(); it != res.end(); it++) {
sort(it->second.begin(),it->second.end());
vector<string> cp(it->second);
ans[index++] = cp;
}
return ans;
}
};