From ebd7763a7e910b7d26dd7f3dbeec5cea63d88f5a Mon Sep 17 00:00:00 2001 From: Karthik Ayyala Date: Sun, 19 Oct 2025 20:19:20 +0530 Subject: [PATCH 1/4] Disjoin set algorithm added to graph section --- .../com/thealgorithms/graph/DisjointSet.java | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/main/java/com/thealgorithms/graph/DisjointSet.java diff --git a/src/main/java/com/thealgorithms/graph/DisjointSet.java b/src/main/java/com/thealgorithms/graph/DisjointSet.java new file mode 100644 index 000000000000..af3eb9671945 --- /dev/null +++ b/src/main/java/com/thealgorithms/graph/DisjointSet.java @@ -0,0 +1,42 @@ +package com.thealgorithms.graph; + +public class DisjointSet { + int[] parent; + int[] rank; + public DisjointSet(int n){ + parent = new int[n]; + rank = new int[n]; + for(int i=0; i Date: Sun, 19 Oct 2025 21:08:28 +0530 Subject: [PATCH 2/4] final version of Merge Accounts using Disjoint set --- .../com/thealgorithms/graph/DisjointSet.java | 121 +++++++++++++++++- 1 file changed, 118 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/thealgorithms/graph/DisjointSet.java b/src/main/java/com/thealgorithms/graph/DisjointSet.java index af3eb9671945..9aef92991c31 100644 --- a/src/main/java/com/thealgorithms/graph/DisjointSet.java +++ b/src/main/java/com/thealgorithms/graph/DisjointSet.java @@ -1,8 +1,34 @@ package com.thealgorithms.graph; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Disjoint Set (Union-Find) Data Structure + * ----------------------------------------- + * This class implements the Disjoint Set Union (DSU) or Union-Find structure, + * which efficiently supports two main operations: + * + * 1. findLeader(x) – Find the representative (leader) of the set that contains element x. + * 2. merge(x, y) – Merge (union) the sets that contain x and y. + * + * Time Complexity (amortized): O(α(N)), where α(N) is the inverse Ackermann function, + * which is very close to constant for all practical input sizes. + */ + public class DisjointSet { - int[] parent; - int[] rank; + + int[] parent; // parent[i] stores the parent (or leader) of node i + int[] rank; // rank[i] stores the approximate depth of the tree rooted at i + + /** + * Constructor: Initializes N disjoint sets (each element is its own leader). + * + * @param n the number of elements + */ public DisjointSet(int n){ parent = new int[n]; rank = new int[n]; @@ -12,31 +38,120 @@ public DisjointSet(int n){ } } + /** + * Finds the leader (representative) of the set that contains x. + * Uses Path Compression to speed up future lookups. + * + * @param x the element whose leader is to be found + * @return the leader of the set containing x + */ + int findLeader(int x){ + // If x is its own parent, it is the leader of its set if(parent[x]==x){ return parent[x]; } + + // Recursively find the leader and compress the path int leader = findLeader(parent[x]); - parent[x] = leader; + parent[x] = leader; // Path compression: directly connect x to its leader return leader; } + /** + * Checks if two elements belong to the same set. + * + * @param x first element + * @param y second element + * @return true if x and y belong to the same set; false otherwise + */ + boolean isSame(int x, int y){ return findLeader(x)==findLeader(y); } + /** + * Merges (unions) the sets containing x and y. + * Uses Union by Rank to attach the smaller tree to the root of the larger one. + * + * @param x first element + * @param y second element + */ + void merge(int x, int y){ int xLeader = findLeader(x); int yLeader = findLeader(y); + // If they already belong to the same set, no action is needed if(xLeader != yLeader){ + // Attach smaller rank tree under larger rank tree if(rank[xLeader]> accountsMerge(List> accountList) { + int accountListSize = accountList.size(); + DisjointSet dsu = new DisjointSet(accountListSize); + + // Maps email to their component index + Map emailGroup = new HashMap<>(); + + for (int i = 0; i < accountListSize; i++) { + int accountSize = accountList.get(i).size(); + + for (int j = 1; j < accountSize; j++) { + String email = accountList.get(i).get(j); + // String accountName = accountList.get(i).get(0); + + // If this is the first time seeing this email then + // assign component group as the account index + if (!emailGroup.containsKey(email)) { + emailGroup.put(email, i); + } else { + // If we have seen this email before then union this + // group with the previous group of the email + dsu.merge(i, emailGroup.get(email)); + } + } + } + + // Store emails corresponding to the component's representative + Map> components = new HashMap>(); + for (String email : emailGroup.keySet()) { + int group = emailGroup.get(email); + int groupRep = dsu.findLeader(group); + + if (!components.containsKey(groupRep)) { + components.put(groupRep, new ArrayList()); + } + + components.get(groupRep).add(email); + } + + // Sort the components and add the account name + List> mergedAccounts = new ArrayList<>(); + for (int group : components.keySet()) { + List component = components.get(group); + Collections.sort(component); + component.add(0, accountList.get(group).get(0)); + mergedAccounts.add(component); + } + + return mergedAccounts; + } + } From c8157a01283d1f13f7fe80ccb2f560ef2295a615 Mon Sep 17 00:00:00 2001 From: Karthik Ayyala Date: Sun, 19 Oct 2025 21:11:46 +0530 Subject: [PATCH 3/4] final working code for merge accounts using Disjoin set --- .../com/thealgorithms/graph/DisjointSet.java | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/thealgorithms/graph/DisjointSet.java b/src/main/java/com/thealgorithms/graph/DisjointSet.java index 9aef92991c31..441a904aca62 100644 --- a/src/main/java/com/thealgorithms/graph/DisjointSet.java +++ b/src/main/java/com/thealgorithms/graph/DisjointSet.java @@ -98,8 +98,8 @@ void merge(int x, int y){ } /** - * this is the code to merge email accounts - * if two accounts share at least one email, they belong to same person. + * This code merges email accounts. + * If two accounts share at least one email address, they are considered to belong to the same person and are merged. * @param accountList * @return */ @@ -155,3 +155,25 @@ public List> accountsMerge(List> accountList) { } } + +/** + * + * this the program for testing the above algorithm + * +public class DisjointSetMain { + public static void main(String[] args) { + List> list = new ArrayList<>(); + list.add(new ArrayList<>(List.of("abc", "abc@mail.com","abx@mail.com"))); + list.add(new ArrayList<>(List.of("abc","abc@mail.com","aby@mail.com"))); + list.add(new ArrayList<>(List.of("Mary","mary@mail.com"))); + list.add(new ArrayList<>(List.of("John","johnnybravo@mail.com"))); + list.add(new ArrayList<>(List.of("John", "johnnybravo@mail.com", "john@mail.com"))); + DisjointSet ds = new DisjointSet(list.size()); + List> ans = ds.accountsMerge(list); + for(List val : ans){ + System.out.println(val); + } + } +} + +*/ \ No newline at end of file From f2015463f1ac3dc88c508de38b50ec9fb4ec2894 Mon Sep 17 00:00:00 2001 From: Karthik Ayyala Date: Sun, 19 Oct 2025 22:19:03 +0530 Subject: [PATCH 4/4] Added Acconts Merge program with Disjont set in Graphs section --- .../com/thealgorithms/graph/DisjointSet.java | 25 +-------- .../thealgorithms/graph/DisjointSetTest.java | 52 +++++++++++++++++++ 2 files changed, 53 insertions(+), 24 deletions(-) create mode 100644 src/test/java/com/thealgorithms/graph/DisjointSetTest.java diff --git a/src/main/java/com/thealgorithms/graph/DisjointSet.java b/src/main/java/com/thealgorithms/graph/DisjointSet.java index 441a904aca62..6eda39d37123 100644 --- a/src/main/java/com/thealgorithms/graph/DisjointSet.java +++ b/src/main/java/com/thealgorithms/graph/DisjointSet.java @@ -153,27 +153,4 @@ public List> accountsMerge(List> accountList) { return mergedAccounts; } - -} - -/** - * - * this the program for testing the above algorithm - * -public class DisjointSetMain { - public static void main(String[] args) { - List> list = new ArrayList<>(); - list.add(new ArrayList<>(List.of("abc", "abc@mail.com","abx@mail.com"))); - list.add(new ArrayList<>(List.of("abc","abc@mail.com","aby@mail.com"))); - list.add(new ArrayList<>(List.of("Mary","mary@mail.com"))); - list.add(new ArrayList<>(List.of("John","johnnybravo@mail.com"))); - list.add(new ArrayList<>(List.of("John", "johnnybravo@mail.com", "john@mail.com"))); - DisjointSet ds = new DisjointSet(list.size()); - List> ans = ds.accountsMerge(list); - for(List val : ans){ - System.out.println(val); - } - } -} - -*/ \ No newline at end of file +} \ No newline at end of file diff --git a/src/test/java/com/thealgorithms/graph/DisjointSetTest.java b/src/test/java/com/thealgorithms/graph/DisjointSetTest.java new file mode 100644 index 000000000000..15090fbb11a4 --- /dev/null +++ b/src/test/java/com/thealgorithms/graph/DisjointSetTest.java @@ -0,0 +1,52 @@ +package com.thealgorithms.graph; + + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import java.util.*; + +public class DisjointSetTest { + + @Test + public void testAccountsMerge() { + // Input data setup + List> list = new ArrayList<>(); + list.add(new ArrayList<>(List.of("abc", "abc@mail.com", "abx@mail.com"))); + list.add(new ArrayList<>(List.of("abc", "abc@mail.com", "aby@mail.com"))); + list.add(new ArrayList<>(List.of("Mary", "mary@mail.com"))); + list.add(new ArrayList<>(List.of("John", "johnnybravo@mail.com"))); + list.add(new ArrayList<>(List.of("John", "johnnybravo@mail.com", "john@mail.com"))); + + // Create instance of your Solution/DisjointSet class + DisjointSet disjointSet = new DisjointSet(list.size()); // or DisjointSet if that’s where accountsMerge() lives + + // Execute the method + List> result = disjointSet.accountsMerge(list); + + // Expected output (order of accounts may vary) + List> expected = new ArrayList<>(); + expected.add(Arrays.asList("abc", "abc@mail.com", "abx@mail.com", "aby@mail.com")); + expected.add(Arrays.asList("Mary", "mary@mail.com")); + expected.add(Arrays.asList("John", "john@mail.com", "johnnybravo@mail.com")); + + // Sort both results for deterministic comparison + sortAccounts(result); + sortAccounts(expected); + + // Verify results + assertEquals(expected, result); + } + + // Helper method to sort emails and accounts for deterministic comparison + private static void sortAccounts(List> accounts) { + for (List acc : accounts) { + // Sort all emails (leave name first) + List emails = acc.subList(1, acc.size()); + Collections.sort(emails); + } + // Sort accounts lexicographically by name + accounts.sort(Comparator.comparing(a -> a.get(0))); + } +} + +