This problem requires merging accounts that share common emails. The key is to use
Union-Find (Disjoint Set Union)
to efficiently group connected emails. First, we
initialize each email as its own parent.
Then, we
union emails
from the same
account.
After grouping, we
collect all emails under
their root parent
and
format the results.
The
path compression in
the
'find' operation
ensures optimal performance.
class Solution { public: // find method is using path compression // With path compression, instead of following the chain every time, // we make each email directly point to the root when we find it. // This way, next time it's an instant lookup. string find(unordered_map<string, string> &parentMap, string email) { if (parentMap[email] != email) { parentMap[email] = find(parentMap, parentMap[email]); } return parentMap[email]; // Traditional find method. // while(parentMap[email]!=email) // email = parentMap[email]; // return parentMap[email]; } vector<vector<string>> accountsMerge(vector<vector<string>>& accounts) { unordered_map<string, string> mailToPerson; // Mail --> Person unordered_map<string, string> parentMap; // Stores Parent of Each Email unordered_map<string, set<string>> parentToAllEmails; // ParentEmail --> All Emails vector<vector<string>> ans; // To store the answer in desired format. // Step-1: Initialization for (int i = 0; i < accounts.size(); i++) { for (int j = 1; j < accounts[i].size(); j++) { mailToPerson.insert({accounts[i][j], accounts[i][0]}); parentMap[accounts[i][j]] = accounts[i][j]; // Initially, each email points to itself. } } // Step-2: Assign Parents (Union Operation) for (int i = 0; i < accounts.size(); i++) { string parentOfFirstEmail = find(parentMap, accounts[i][1]); // Find parent of first email for (int j = 2; j < accounts[i].size(); j++) { string parentOfOtherEmails = find(parentMap, accounts[i][j]); parentMap[parentOfOtherEmails] = parentOfFirstEmail; } } // Step-3: Group Emails under their Parent for (vector<string> entity : accounts) { string parentOfFirstEmail = find(parentMap, entity[1]); for (int i = 1; i < entity.size(); i++) { parentToAllEmails[parentOfFirstEmail].insert(entity[i]); } } // Step-4: Build the result in the required format. for (auto itr = parentToAllEmails.begin(); itr != parentToAllEmails.end(); itr++) { string personName = mailToPerson[itr->first]; set<string> emails = itr->second; vector<string> mergedAccount(emails.begin(),emails.end()); mergedAccount.insert(mergedAccount.begin(), personName); ans.push_back(mergedAccount); } return ans; } };
Where n is the total number of emails and α is the inverse Ackermann function (nearly constant time due to path compression).
We use O(n) space to store parent relationships, email mappings, and the final result.