From 4512de0055f107907d479a4dec52c0e1862f9261 Mon Sep 17 00:00:00 2001 From: Sean Prashad <13009507+SeanPrashad@users.noreply.github.com> Date: Fri, 19 Mar 2021 00:32:31 -0400 Subject: [PATCH] Use Union Find approach for 721_Accounts_Merge.java --- Graphs/721_Accounts_Merge.java | 93 ++++++++++++++++++++++--------- Graphs/721_Accounts_Merge_UF.java | 91 ------------------------------ 2 files changed, 68 insertions(+), 116 deletions(-) delete mode 100644 Graphs/721_Accounts_Merge_UF.java diff --git a/Graphs/721_Accounts_Merge.java b/Graphs/721_Accounts_Merge.java index aa3e7f55..dd0249dd 100644 --- a/Graphs/721_Accounts_Merge.java +++ b/Graphs/721_Accounts_Merge.java @@ -2,47 +2,90 @@ class Solution { public List> accountsMerge(List> accounts) { List> result = new ArrayList<>(); - Map> graph = new HashMap<>(); - Map emailsToNames = new HashMap<>(); + int n = accounts.size(); - for (List account : accounts) { - String name = account.get(0); + UnionFind uf = new UnionFind(n); - for (int i = 1; i < account.size(); i++) { - graph.putIfAbsent(account.get(i), new HashSet<>()); - emailsToNames.put(account.get(i), name); + Map emailToAccountIdx = new HashMap<>(); - if (i == 1) { - continue; - } + /* + * If we've seen an e-mail before, it means that it belongs to a previous + * account! All we need to do is grab the idx of the account that it belongs to + * and update our parents[] array in our UnionFind object using the union() + * method + */ + for (int i = 0; i < accounts.size(); i++) { + for (int j = 1; j < accounts.get(i).size(); j++) { + String email = accounts.get(i).get(j); - graph.get(account.get(i)).add(account.get(i - 1)); - graph.get(account.get(i - 1)).add(account.get(i)); + if (emailToAccountIdx.containsKey(email)) { + /* + * If we've seen this e-mail before, it means that all e-mails in this new + * account actually belong to an existing user + * + * In this case, we can grab the account index of the user we've previously + * encountered and set it as the parent for this account + * + * For example, if account ID 2 already had "johnsmith@mail.com" and for account + * 7, we encounter "johnsmith@mail.com" once more, it means that ALL emails in + * account 7 actually belong to account 2! + * + * How do we represent this? By setting the parent of account 7 to point to + * account 2, or in more general terms, setting the parent ID of the current + * account to be the ID of the account for the email we've previously seen + */ + int previousParent = emailToAccountIdx.get(email); + uf.union(previousParent, i); + } else { + emailToAccountIdx.put(email, i); + } } } - Set visited = new HashSet<>(); + Map> accountEmails = new HashMap<>(); - for (String key : graph.keySet()) { + for (int i = 0; i < accounts.size(); i++) { + int parent = uf.findParent(i); + List emails = accounts.get(i); + + accountEmails.putIfAbsent(parent, new HashSet<>()); + accountEmails.get(parent).addAll(emails.subList(1, emails.size())); + } + + for (int key : accountEmails.keySet()) { List temp = new ArrayList<>(); - if (visited.add(key)) { - dfs(graph, visited, key, temp); - Collections.sort(temp); - temp.add(0, emailsToNames.get(key)); - result.add(temp); - } + temp.addAll(accountEmails.get(key)); + Collections.sort(temp); + temp.add(0, accounts.get(key).get(0)); + result.add(temp); } return result; } - private void dfs(Map> graph, Set visited, String email, List temp) { - temp.add(email); + private class UnionFind { + private int[] parents; + + public UnionFind(int n) { + parents = new int[n]; - for (String neighbour : graph.get(email)) { - if (visited.add(neighbour)) { - dfs(graph, visited, neighbour, temp); + for (int i = 0; i < n; i++) { + parents[i] = i; } } + + public int findParent(int account) { + if (parents[account] == account) { + return account; + } + + parents[account] = findParent(parents[account]); + return parents[account]; + } + + public void union(int p1, int p2) { + int i = findParent(p1), j = findParent(p2); + parents[j] = i; + } } } diff --git a/Graphs/721_Accounts_Merge_UF.java b/Graphs/721_Accounts_Merge_UF.java deleted file mode 100644 index dd0249dd..00000000 --- a/Graphs/721_Accounts_Merge_UF.java +++ /dev/null @@ -1,91 +0,0 @@ -class Solution { - public List> accountsMerge(List> accounts) { - List> result = new ArrayList<>(); - - int n = accounts.size(); - - UnionFind uf = new UnionFind(n); - - Map emailToAccountIdx = new HashMap<>(); - - /* - * If we've seen an e-mail before, it means that it belongs to a previous - * account! All we need to do is grab the idx of the account that it belongs to - * and update our parents[] array in our UnionFind object using the union() - * method - */ - for (int i = 0; i < accounts.size(); i++) { - for (int j = 1; j < accounts.get(i).size(); j++) { - String email = accounts.get(i).get(j); - - if (emailToAccountIdx.containsKey(email)) { - /* - * If we've seen this e-mail before, it means that all e-mails in this new - * account actually belong to an existing user - * - * In this case, we can grab the account index of the user we've previously - * encountered and set it as the parent for this account - * - * For example, if account ID 2 already had "johnsmith@mail.com" and for account - * 7, we encounter "johnsmith@mail.com" once more, it means that ALL emails in - * account 7 actually belong to account 2! - * - * How do we represent this? By setting the parent of account 7 to point to - * account 2, or in more general terms, setting the parent ID of the current - * account to be the ID of the account for the email we've previously seen - */ - int previousParent = emailToAccountIdx.get(email); - uf.union(previousParent, i); - } else { - emailToAccountIdx.put(email, i); - } - } - } - - Map> accountEmails = new HashMap<>(); - - for (int i = 0; i < accounts.size(); i++) { - int parent = uf.findParent(i); - List emails = accounts.get(i); - - accountEmails.putIfAbsent(parent, new HashSet<>()); - accountEmails.get(parent).addAll(emails.subList(1, emails.size())); - } - - for (int key : accountEmails.keySet()) { - List temp = new ArrayList<>(); - temp.addAll(accountEmails.get(key)); - Collections.sort(temp); - temp.add(0, accounts.get(key).get(0)); - result.add(temp); - } - - return result; - } - - private class UnionFind { - private int[] parents; - - public UnionFind(int n) { - parents = new int[n]; - - for (int i = 0; i < n; i++) { - parents[i] = i; - } - } - - public int findParent(int account) { - if (parents[account] == account) { - return account; - } - - parents[account] = findParent(parents[account]); - return parents[account]; - } - - public void union(int p1, int p2) { - int i = findParent(p1), j = findParent(p2); - parents[j] = i; - } - } -}