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.