Accounts Merge Solutions in C++
Number 721
Difficulty Medium
Acceptance 48.9%
Link LeetCode
Other languages Go
Solutions
C++ solution by haoel/leetcode
// Source : https://leetcode.com/problems/accounts-merge/// Author : Hao Chen// Date : 2019-03-29//Bad Performance Solutionclass Solution_Time_Limit_Exceeded {public:// We can orginze all relevant emails to a chain,// then we can use Union Find algorithm// Besides, we also need to map the relationship between name and email.vector<vector<string>> accountsMerge(vector<vector<string>>& accounts) {unordered_map<string, string> emails_chains; // email chainsunordered_map<string, string> names; // names to email chains' head//initializationfor(int i = 0 ; i<accounts.size();i++) {auto& account = accounts[i];auto& name = account[0];for (int j=1; j<account.size(); j++) {auto& email = account[j];if ( names.find(email) == names.end() ) {emails_chains[email] = email;names[email] = name;}join(emails_chains, account[1], email);}}//reform the emailsunordered_map<string, set<string>> res;for( auto& acc : accounts ) {string e = find(emails_chains, acc[1]);res[e].insert(acc.begin()+1, acc.end());}//output the resultvector<vector<string>> result;for (auto pair : res) {vector<string> emails(pair.second.begin(), pair.second.end());emails.insert(emails.begin(), names[pair.first]);result.push_back(emails);}return result;}string find(unordered_map<string, string>& emails_chains,string email) {while( email != emails_chains[email] ){email = emails_chains[email];}return email;}bool join(unordered_map<string, string>& emails_chains,string& email1, string& email2) {string e1 = find(emails_chains, email1);string e2 = find(emails_chains, email2);if ( e1 != e2 ) emails_chains[e1] = email2;return e1 == e2;}};//// Performance Tunning// -----------------//// The above algorithm need to do string comparison, it causes lots of efforts// So, we allocated the ID for each email, and compare the ID would save the time.//// Furthermore, we can use the Group-Email-ID instead of email ID,// this would save more time.//class Solution {public:// We can orginze all relevant emails to a chain,// then we can use Union Find algorithm// Besides, we also need to map the relationship between name and email.vector<vector<string>> accountsMerge(vector<vector<string>>& accounts) {unordered_map<string, int> emails_id; //using email ID for union findunordered_map<int, int> emails_chains; // email chainsunordered_map<int, string> names; // email id & name//initialization & joinfor(int i = 0 ; i<accounts.size();i++) {// using the account index as the emails group ID,// this could simplify the emails chain.emails_chains[i] = i;auto& account = accounts[i];auto& name = account[0];for (int j=1; j<account.size(); j++) {auto& email = account[j];if ( emails_id.find(email) == emails_id.end() ) {emails_id[email] = i;names[i] = name;}else {join( emails_chains, i, emails_id[email] );}}}//reform the emailsunordered_map<int, set<string>> res;for(int i=0; i<accounts.size(); i++) {int idx = find(emails_chains, i);res[idx].insert(accounts[i].begin()+1, accounts[i].end());}//output the resultvector<vector<string>> result;for (auto pair : res) {vector<string> emails( pair.second.begin(), pair.second.end() );emails.insert(emails.begin(), names[pair.first]);result.push_back(emails);}return result;}int find(unordered_map<int, int>& emails_chains, int id) {while( id != emails_chains[id] ){id = emails_chains[id];}return id;}bool join(unordered_map<int, int>& emails_chains, int id1, int id2) {int e1 = find(emails_chains, id1);int e2 = find(emails_chains, id2);if ( e1 != e2 ) emails_chains[e1] = e2;return e1 == e2;}};
C++ solution by liuyubobobo/Play-Leetcode
/// Source : https://leetcode.com/problems/accounts-merge/description//// Author : liuyubobobo/// Time : 2017-11-25#include <iostream>#include <vector>#include <map>#include <unordered_map>#include <unordered_set>using namespace std;/// Using DFS/// Time Complexity: O(len(emails)^2)/// Space Complexity: O(len(emails))class Solution {public:vector<vector<string>> accountsMerge(vector<vector<string>>& accounts) {map<string, string> emailToName;for(const vector<string>& account: accounts)for(int i = 1 ; i < account.size() ; i ++)emailToName[account[i]] = account[0];unordered_map<string, int> emailIndex;int index = 0;for(const pair<string, string>& p: emailToName)emailIndex.insert(make_pair(p.first, index ++));vector<string> intToEmail(emailIndex.size(), "");for(const pair<string, int>& p: emailIndex)intToEmail[p.second] = p.first;vector<unordered_set<int>> g(emailIndex.size(), unordered_set<int>());for(const vector<string>& account: accounts){for(int i = 1 ; i < account.size() ; i ++)for(int j = i + 1; j < account.size() ; j ++){int index1 = emailIndex[account[i]];int index2 = emailIndex[account[j]];g[index1].insert(index2);g[index2].insert(index1);}}vector<vector<string>> res;vector<bool> flag(emailIndex.size(), false);for(const pair<string, string>& p: emailToName){int index = emailIndex[p.first];if(!flag[index]){vector<string> emails;dfs(g, index, flag, emails, intToEmail);sort(emails.begin(), emails.end());string name = emailToName[emails[0]];vector<string> tres;tres.push_back(name);for(const string& email: emails)tres.push_back(email);res.push_back(tres);}}return res;}private:void dfs(const vector<unordered_set<int>>& g, int v, vector<bool>& flag,vector<string>& res, const vector<string>& intToEmail){res.push_back(intToEmail[v]);flag[v] = true;for(int next: g[v])if(!flag[next])dfs(g, next, flag, res, intToEmail);}};void printRes(const vector<vector<string>> res){for(const vector<string>& row: res){for(const string& e: row)cout << e << " ";cout << endl;}}int main() {vector<vector<string>> accounts = {{"John", "johnsmith@mail.com", "john00@mail.com"},{"John", "johnnybravo@mail.com"},{"John", "johnsmith@mail.com", "john_newyork@mail.com"},{"Mary", "mary@mail.com"}};printRes(Solution().accountsMerge(accounts));return 0;}
C++ solution by liuyubobobo/Play-Leetcode
/// Source : https://leetcode.com/problems/accounts-merge/description//// Author : liuyubobobo/// Time : 2017-11-25#include <iostream>#include <vector>#include <map>#include <unordered_map>#include <unordered_set>#include <cassert>using namespace std;/// Using Union-Find/// Time Complexity: O(len(emails))/// Space Complexity: O(len(emails))class UnionFind{private:// rank[i]表示以i为根的集合所表示的树的层数// 在后续的代码中, 我们并不会维护rank的语意, 也就是rank的值在路径压缩的过程中, 有可能不在是树的层数值// 这也是我们的rank不叫height或者depth的原因, 他只是作为比较的一个标准// 关于这个问题,可以参考问答区:http://coding.imooc.com/learn/questiondetail/7287.htmlint* rank;int* parent; // parent[i]表示第i个元素所指向的父节点int count; // 数据个数public:// 构造函数UnionFind(int count){parent = new int[count];rank = new int[count];this->count = count;for( int i = 0 ; i < count ; i ++ ){parent[i] = i;rank[i] = 1;}}// 析构函数~UnionFind(){delete[] parent;delete[] rank;}// 查找过程, 查找元素p所对应的集合编号// O(h)复杂度, h为树的高度int find(int p){assert( p >= 0 && p < count );// path compression 1while( p != parent[p] ){parent[p] = parent[parent[p]];p = parent[p];}return p;}// 查看元素p和元素q是否所属一个集合// O(h)复杂度, h为树的高度bool isConnected( int p , int q ){return find(p) == find(q);}// 合并元素p和元素q所属的集合// O(h)复杂度, h为树的高度void unionElements(int p, int q){int pRoot = find(p);int qRoot = find(q);if( pRoot == qRoot )return;// 根据两个元素所在树的元素个数不同判断合并方向// 将元素个数少的集合合并到元素个数多的集合上if( rank[pRoot] < rank[qRoot] ){parent[pRoot] = qRoot;}else if( rank[qRoot] < rank[pRoot]){parent[qRoot] = pRoot;}else{ // rank[pRoot] == rank[qRoot]parent[pRoot] = qRoot;rank[qRoot] += 1; // 此时, 我维护rank的值}}};class Solution {public:vector<vector<string>> accountsMerge(vector<vector<string>>& accounts) {map<string, string> emailToName;for(const vector<string>& account: accounts)for(int i = 1 ; i < account.size() ; i ++)emailToName[account[i]] = account[0];unordered_map<string, int> emailIndex;int index = 0;for(const pair<string, string>& p: emailToName)emailIndex.insert(make_pair(p.first, index ++));vector<string> intToEmail(emailIndex.size(), "");for(const pair<string, int>& p: emailIndex)intToEmail[p.second] = p.first;UnionFind uf(emailIndex.size());for(const vector<string>& account: accounts){int index1 = emailIndex[account[1]];for(int i = 2 ; i < account.size() ; i ++){int index2 = emailIndex[account[i]];uf.unionElements(index1, index2);}}vector<vector<string>> res;vector<bool> flag(emailIndex.size(), false);for(int i = 0 ; i < emailIndex.size() ; i ++)if(!flag[i]){vector<string> emails;emails.push_back(intToEmail[i]);flag[i] = true;for(int j = i + 1 ; j < emailIndex.size() ; j ++)if(!flag[j] && uf.isConnected(i, j)){flag[j] = true;emails.push_back(intToEmail[j]);}sort(emails.begin(), emails.end());string name = emailToName[emails[0]];vector<string> tres;tres.push_back(name);for(const string& email: emails)tres.push_back(email);res.push_back(tres);}return res;}};void printRes(const vector<vector<string>> res){for(const vector<string>& row: res){for(const string& e: row)cout << e << " ";cout << endl;}}int main() {vector<vector<string>> accounts = {{"John", "johnsmith@mail.com", "john00@mail.com"},{"John", "johnnybravo@mail.com"},{"John", "johnsmith@mail.com", "john_newyork@mail.com"},{"Mary", "mary@mail.com"}};printRes(Solution().accountsMerge(accounts));return 0;}