721. 账户合并
      
        给定一个列表 accounts,每个元素 accounts[i] 是一个字符串列表,其中第一个元素 accounts[i][0] 是 名称 (name),其余元素是 emails 表示该账户的邮箱地址
现在,我们想合并这些账户。如果两个账户都有一些共同的邮箱地址,则两个账户必定属于同一个人。请注意,即使两个账户具有相同的名称,它们也可能属于不同的人,因为人们可能具有相同的名称。一个人最初可以拥有任意数量的账户,但其所有账户都具有相同的名称
合并账户后,按以下格式返回账户:每个账户的第一个元素是名称,其余元素是 按字符 ASCII 顺序排列 的邮箱地址。账户本身可以以 任意顺序 返回
示例 1
输入:accounts = [[“John”, “johnsmith@mail.com“, “john00@mail.com“], [“John”, “johnnybravo@mail.com“], [“John”, “johnsmith@mail.com“, “john_newyork@mail.com“], [“Mary”, “mary@mail.com“]]
输出:[[“John”, ‘john00@mail.com‘, ‘john_newyork@mail.com‘, ‘johnsmith@mail.com‘],  [“John”, “johnnybravo@mail.com“], [“Mary”, “mary@mail.com“]]
解释:第一个和第三个 John 是同一个人,因为他们有共同的邮箱地址 “johnsmith@mail.com“。
第二个 John 和 Mary 是不同的人,因为他们的邮箱地址没有被其他帐户使用。
可以以任何顺序返回这些列表,例如答案 [[‘Mary’,‘mary@mail.com‘],[‘John’,‘johnnybravo@mail.com‘],
[‘John’,‘john00@mail.com‘,‘john_newyork@mail.com‘,‘johnsmith@mail.com‘]] 也是正确的
示例 2
输入:accounts = [[“Gabe”,”Gabe0@m.co“,”Gabe3@m.co“,”Gabe1@m.co“],[“Kevin”,”Kevin3@m.co“,”Kevin5@m.co“,”Kevin0@m.co“],[“Ethan”,”Ethan5@m.co“,”Ethan4@m.co“,”Ethan0@m.co“],[“Hanzo”,”Hanzo3@m.co“,”Hanzo1@m.co“,”Hanzo0@m.co“],[“Fern”,”Fern5@m.co“,”Fern1@m.co“,”Fern0@m.co“]]
输出:[[“Ethan”,”Ethan0@m.co“,”Ethan4@m.co“,”Ethan5@m.co“],[“Gabe”,”Gabe0@m.co“,”Gabe1@m.co“,”Gabe3@m.co“],[“Hanzo”,”Hanzo0@m.co“,”Hanzo1@m.co“,”Hanzo3@m.co“],[“Kevin”,”Kevin0@m.co“,”Kevin3@m.co“,”Kevin5@m.co“],[“Fern”,”Fern0@m.co“,”Fern1@m.co“,”Fern5@m.co“]]
提示
邮箱相同,用户就相同
Solution 1
第一次尝试,通过深度优先搜索解答
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
   | class Solution {     public List<List<String>> accountsMerge(List<List<String>> accounts) {         Set<String> existEmails = new HashSet<>();         Set<Integer> existIdxs = new HashSet<>();         List<List<String>> merged = new ArrayList<>();         List<String> temp;
          for (List<String> ignored : accounts) {             temp = new ArrayList<>();             dfs(existEmails, existIdxs, temp, accounts);             if (!temp.isEmpty()) {                 if (temp.size() > 2) {                     Set<String> emailSet = new HashSet<>(temp.subList(1, temp.size()));                     List<String> emails = new ArrayList<>(emailSet);                     Collections.sort(emails);                     List<String> list = new ArrayList<>();                     list.add(temp.get(0));                     list.addAll(emails);                     merged.add(list);                 } else {                     merged.add(temp);                 }             }         }
          return merged;     }
      private void dfs(Set<String> existEmails,                      Set<Integer> existIdxs,                     List<String> temp,                      List<List<String>> accounts) {         for (int i = 0, k = accounts.size(); i < k; i++) {             if (!existIdxs.contains(i)) {                 List<String> emails = accounts.get(i).subList(1, accounts.get(i).size());                 if (temp.isEmpty()) {                     temp.addAll(accounts.get(i));                     existIdxs.add(i);                     existEmails.addAll(emails);                 } else {                     boolean merged = false;                     for (String email : emails) {                         if (existEmails.contains(email)) {                             merged = true;                             break;                         }                     }                     if (merged) {                         existIdxs.add(i);                         existEmails.addAll(emails);                         temp.addAll(emails);                         dfs(existEmails, existIdxs, temp, accounts);                     }                 }             }         }     } }
  | 
 
- 执行用时:469 ms(击败 6.28% 使用 Java 的用户)
 
- 内存消耗:50.55 MB(击败 5.00% 使用 Java 的用户)
 
Solution 2
推荐解法,通过 并查集 解答
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
   | class Solution {     public List<List<String>> accountsMerge(List<List<String>> accounts) {         Map<String, Integer> email2Index = new HashMap<>();         Map<String, String> email2Name = new HashMap<>();
          int emailIdx = 0;         int count = 0;         for (List<String> account : accounts) {             String name = account.get(0);             count = account.size();             for (int i = 1; i < count; i++) {                 String email = account.get(i);                 if (!email2Index.containsKey(email)) {                     email2Index.put(email, emailIdx++);                     email2Name.put(email, name);                 }             }         }
          UnionFind uf = new UnionFind(emailIdx);         for (List<String> account : accounts) {             String firstEmail = account.get(1);             int firstIdx = email2Index.get(firstEmail);             for (int i = 2, k = account.size(); i < k; i++) {                 String nextEmail = account.get(i);                 int nextIdx = email2Index.get(nextEmail);                 uf.union(firstIdx, nextIdx);             }         }
          Map<Integer, List<String>> emailIdxMap = new HashMap<>();         email2Index.forEach((k, v) -> {             int rootIdx = uf.find(v);             List<String> emails = emailIdxMap.getOrDefault(rootIdx, new ArrayList<>());             emails.add(k);             emailIdxMap.put(rootIdx, emails);         });
          List<List<String>> merged = new ArrayList<>();         List<String> val;         for (List<String> emails : emailIdxMap.values()) {             Collections.sort(emails);             String name = email2Name.get(emails.get(0));             val = new ArrayList<>();             val.add(name);             val.addAll(emails);             merged.add(val);         }
          return merged;     }
      private static class UnionFind {
          int[] node;
          public UnionFind(int size) {             node = new int[size];             for (int i = 0; i < size; i++) {                 node[i] = i;             }         }
          public void union(int index1, int index2) {             node[find(index2)] = find(index1);         }
          public int find(int index) {             if (node[index] != index) {                 node[index] = find(node[index]);             }             return node[index];         }     } }
  | 
 
- 执行用时:28 ms(击败 94.76% 使用 Java 的用户)
 
- 内存消耗:47.93 MB(击败 32.94% 使用 Java 的用户)
 
Source
721. 账户合并 - 力扣(LeetCode)