diff --git a/README.md b/README.md index 273a5d5fd..c58a49802 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ LeetCode |771|[Jewels and Stones](https://leetcode.com/problems/jewels-and-stones/description) | [C++](./algorithms/cpp/jewelsAndStones/JewelsAndStones.cpp)|Easy| |747|[Largest Number At Least Twice of Others](https://leetcode.com/problems/largest-number-at-least-twice-of-others/) | [Python](./algorithms/python/LargestNumberAtLeastTwiceOfOthers/dominantIndex.py)|Easy| |746|[Min Cost Climbing Stairs](https://leetcode.com/problems/min-cost-climbing-stairs/) | [C++](./algorithms/cpp/minCostClimbingStairs/MinCostClimbingStairs.cpp), [Python](./algorithms/python/MinCostClimbingStairs/minCostClimbingStairs.py)|Easy| +|721|[Accounts Merge](https://leetcode.com/problems/accounts-merge/) | [C++](./algorithms/cpp/accountsMerge/AccountsMerge.cpp)|Medium| |717|[1-bit and 2-bit Characters](https://leetcode.com/problems/1-bit-and-2-bit-characters/) | [Python](./algorithms/python/1-bitAnd2-bitCharacters/isOneBitCharacter.py)|Easy| |714|[Best Time to Buy and Sell Stock with Transaction Fee](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee) | [C++](./algorithms/cpp/bestTimeToBuyAndSellStock/BestTimeToBuyAndSellStockWithTransactionFee.cpp)|Medium| |712|[Minimum ASCII Delete Sum for Two Strings](https://leetcode.com/problems/minimum-ascii-delete-sum-for-two-strings/) | [C++](./algorithms/cpp/minimumASCIIDeleteSumForTwoStrings/MinimumAsciiDeleteSumForTwoStrings.cpp)|Medium| diff --git a/algorithms/cpp/accountsMerge/AccountsMerge.cpp b/algorithms/cpp/accountsMerge/AccountsMerge.cpp new file mode 100644 index 000000000..e9ee405fa --- /dev/null +++ b/algorithms/cpp/accountsMerge/AccountsMerge.cpp @@ -0,0 +1,174 @@ +// Source : https://leetcode.com/problems/accounts-merge/ +// Author : Hao Chen +// Date : 2019-03-29 + +/***************************************************************************************************** + * + * 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. + * + * Note: + * The length of accounts will be in the range [1, 1000]. + * The length of accounts[i] will be in the range [1, 10]. + * The length of accounts[i][j] will be in the range [1, 30]. + ******************************************************************************************************/ + + +//Bad Performance Solution +class 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> accountsMerge(vector>& accounts) { + unordered_map emails_chains; // email chains + unordered_map names; // names to email chains' head + + //initialization + for(int i = 0 ; i> res; + for( auto& acc : accounts ) { + string e = find(emails_chains, acc[1]); + res[e].insert(acc.begin()+1, acc.end()); + } + + //output the result + vector> result; + for (auto pair : res) { + vector emails(pair.second.begin(), pair.second.end()); + emails.insert(emails.begin(), names[pair.first]); + result.push_back(emails); + } + return result; + } + + string find(unordered_map& emails_chains, + string email) { + while( email != emails_chains[email] ){ + email = emails_chains[email]; + } + return email; + } + + bool join(unordered_map& 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> accountsMerge(vector>& accounts) { + unordered_map emails_id; //using email ID for union find + unordered_map emails_chains; // email chains + unordered_map names; // email id & name + + //initialization & join + for(int i = 0 ; i> res; + for(int i=0; i> result; + for (auto pair : res) { + vector emails( pair.second.begin(), pair.second.end() ); + emails.insert(emails.begin(), names[pair.first]); + result.push_back(emails); + } + return result; + } + + int find(unordered_map& emails_chains, int id) { + while( id != emails_chains[id] ){ + id = emails_chains[id]; + } + return id; + } + + bool join(unordered_map& emails_chains, int id1, int id2) { + int e1 = find(emails_chains, id1); + int e2 = find(emails_chains, id2); + if ( e1 != e2 ) emails_chains[e1] = id2; + return e1 == e2; + } +};