/// <summary> /// Leetcode 721 /// https://leetcode.com/problems/accounts-merge/ /// </summary> /// <param name="accounts"></param> /// <returns></returns> public static IList <IList <string> > AccountsMerge(IList <IList <string> > accounts) { var emailSet = getAllEmails(accounts); // https://leetcode.com/problems/accounts-merge/discuss/164699/C-Solution-(Union-Find)-beats-91.49 var emailList = emailSet.ToList(); var ordCmp = StringComparer.Ordinal; emailList.Sort(ordCmp); var emailNameMap = getEmailNameMap(accounts); var emailIdmap = new Dictionary <string, int>(); int index = 0; var emailLookup = new List <string>(); foreach (var item in emailList) { emailIdmap.Add(item, index); index++; emailLookup.Add(item); } var unionFind = new QuickUnion(emailSet.Count); unionFind.EmailIdMap = emailIdmap; foreach (var list in accounts) { for (int i = 1; i < list.Count - 1; i++) { var email1 = list[i]; var email2 = list[i + 1]; var connected = unionFind.Connected(email1, email2); if (!connected) { unionFind.Union(email1, email2); } } } // flat the tree for (int i = 0; i < emailSet.Count; i++) { unionFind.QuickFindAndPathCompression(i); } var dict = new Dictionary <int, List <string> >(); var parent = unionFind.GetParent(); for (int i = 0; i < parent.Length; i++) { var key = parent[i]; if (!dict.ContainsKey(key)) { dict.Add(key, new List <string>()); } dict[key].Add(emailLookup[i]); } // output a list var result = new List <IList <string> >(); foreach (var item in dict.Keys) { var list = new List <string>(); var email = emailLookup[item]; var name = emailNameMap[email]; list.Add(name); var values = dict[item]; list.AddRange(values); result.Add(list); } return(result); }