這題仍然就是並查集的基本操作,難點在於建模困難,怎麼將這個賬戶、郵箱合併的問題轉換爲最原始的並查集問題。
如何建模:
① 將username
進行1~n的編號,username纔是我們並查集要處理的元素對象,而不是郵箱。
② 利用map<string,int>
將每一個郵箱地址字符串映射到它的用戶名,也就是上面的1~n。
③ 如果郵箱字符串發生了重複,將當前郵箱的用戶i
和與它重複的字符串的用戶j
進行並查集的合併操作。
④ 最終,一共有多少個不同的並查集,就有多少個不同的用戶。遍歷1~n,利用map<int,vector<int>>
來存儲一個代表元有多少個用戶名(當然,實際上都是他自己)。
⑤ 根據map<int<vector<int>>
得出答案,中間用set<string>
存儲郵箱,爲了去重加排序。
struct UFS{
int f[1010];
UFS(){
for(int i=0;i<1010;i++){
f[i] = i;
}
}
int find(int x){
return x==f[x]?x:f[x]=find(f[x]);
}
void merge(int x,int y){
f[find(x)] = find(y);
}
};
class Solution {
public:
vector<vector<string>> accountsMerge(vector<vector<string>>& accounts) {
map<string,int> mailID;
UFS ufs;
for(int i=0;i<accounts.size();i++){
for(int j=1;j<accounts[i].size();j++){
if(mailID.count(accounts[i][j])){
int id = mailID[accounts[i][j]];
ufs.merge(id,i);
}else{
mailID[accounts[i][j]] = i;
}
}
}
map<int,vector<int>> res;
for(int i=0;i<accounts.size();i++){
int fa = ufs.find(i);
// cout<<i<<" "<<fa<<endl;
if(!res.count(fa)){
res[fa] = vector<int>{i};
}else{
res[fa].push_back(i);
}
}
cout<<res.size()<<endl;
vector<vector<string>> ans;
map<int,vector<int>>::iterator it = res.begin();
for(;it!=res.end();it++){
vector<string> v;
set<string> s;
v.push_back(accounts[it->first][0]);
for(int i:it->second){
for(int j=1;j<accounts[i].size();j++){
s.insert(accounts[i][j]);
}
}
for(set<string>::iterator itt = s.begin();itt!=s.end();itt++){
v.push_back(*itt);
}
ans.push_back(v);
}
return ans;
}
};