11package com .thealgorithms .graph ;
22
3+ import java .util .ArrayList ;
4+ import java .util .Collections ;
5+ import java .util .HashMap ;
6+ import java .util .List ;
7+ import java .util .Map ;
8+
9+ /**
10+ * Disjoint Set (Union-Find) Data Structure
11+ * -----------------------------------------
12+ * This class implements the Disjoint Set Union (DSU) or Union-Find structure,
13+ * which efficiently supports two main operations:
14+ *
15+ * 1. findLeader(x) – Find the representative (leader) of the set that contains element x.
16+ * 2. merge(x, y) – Merge (union) the sets that contain x and y.
17+ *
18+ * Time Complexity (amortized): O(α(N)), where α(N) is the inverse Ackermann function,
19+ * which is very close to constant for all practical input sizes.
20+ */
21+
322public class DisjointSet {
4- int [] parent ;
5- int [] rank ;
23+
24+ int [] parent ; // parent[i] stores the parent (or leader) of node i
25+ int [] rank ; // rank[i] stores the approximate depth of the tree rooted at i
26+
27+ /**
28+ * Constructor: Initializes N disjoint sets (each element is its own leader).
29+ *
30+ * @param n the number of elements
31+ */
632 public DisjointSet (int n ){
733 parent = new int [n ];
834 rank = new int [n ];
@@ -12,31 +38,120 @@ public DisjointSet(int n){
1238 }
1339 }
1440
41+ /**
42+ * Finds the leader (representative) of the set that contains x.
43+ * Uses Path Compression to speed up future lookups.
44+ *
45+ * @param x the element whose leader is to be found
46+ * @return the leader of the set containing x
47+ */
48+
1549 int findLeader (int x ){
50+ // If x is its own parent, it is the leader of its set
1651 if (parent [x ]==x ){
1752 return parent [x ];
1853 }
54+
55+ // Recursively find the leader and compress the path
1956 int leader = findLeader (parent [x ]);
20- parent [x ] = leader ;
57+ parent [x ] = leader ; // Path compression: directly connect x to its leader
2158 return leader ;
2259 }
2360
61+ /**
62+ * Checks if two elements belong to the same set.
63+ *
64+ * @param x first element
65+ * @param y second element
66+ * @return true if x and y belong to the same set; false otherwise
67+ */
68+
2469 boolean isSame (int x , int y ){
2570 return findLeader (x )==findLeader (y );
2671 }
2772
73+ /**
74+ * Merges (unions) the sets containing x and y.
75+ * Uses Union by Rank to attach the smaller tree to the root of the larger one.
76+ *
77+ * @param x first element
78+ * @param y second element
79+ */
80+
2881 void merge (int x , int y ){
2982 int xLeader = findLeader (x );
3083 int yLeader = findLeader (y );
84+ // If they already belong to the same set, no action is needed
3185 if (xLeader != yLeader ){
86+ // Attach smaller rank tree under larger rank tree
3287 if (rank [xLeader ]<rank [yLeader ]){
3388 parent [xLeader ] = yLeader ;
3489 }else {
3590 parent [yLeader ] = xLeader ;
91+
92+ // If ranks are equal, increment the rank of the new root
3693 if (rank [xLeader ] == rank [yLeader ]){
3794 rank [xLeader ] += 1 ;
3895 }
3996 }
4097 }
4198 }
99+
100+ /**
101+ * this is the code to merge email accounts
102+ * if two accounts share at least one email, they belong to same person.
103+ * @param accountList
104+ * @return
105+ */
106+ public List <List <String >> accountsMerge (List <List <String >> accountList ) {
107+ int accountListSize = accountList .size ();
108+ DisjointSet dsu = new DisjointSet (accountListSize );
109+
110+ // Maps email to their component index
111+ Map <String , Integer > emailGroup = new HashMap <>();
112+
113+ for (int i = 0 ; i < accountListSize ; i ++) {
114+ int accountSize = accountList .get (i ).size ();
115+
116+ for (int j = 1 ; j < accountSize ; j ++) {
117+ String email = accountList .get (i ).get (j );
118+ // String accountName = accountList.get(i).get(0);
119+
120+ // If this is the first time seeing this email then
121+ // assign component group as the account index
122+ if (!emailGroup .containsKey (email )) {
123+ emailGroup .put (email , i );
124+ } else {
125+ // If we have seen this email before then union this
126+ // group with the previous group of the email
127+ dsu .merge (i , emailGroup .get (email ));
128+ }
129+ }
130+ }
131+
132+ // Store emails corresponding to the component's representative
133+ Map <Integer , List <String >> components = new HashMap <Integer , List <String >>();
134+ for (String email : emailGroup .keySet ()) {
135+ int group = emailGroup .get (email );
136+ int groupRep = dsu .findLeader (group );
137+
138+ if (!components .containsKey (groupRep )) {
139+ components .put (groupRep , new ArrayList <String >());
140+ }
141+
142+ components .get (groupRep ).add (email );
143+ }
144+
145+ // Sort the components and add the account name
146+ List <List <String >> mergedAccounts = new ArrayList <>();
147+ for (int group : components .keySet ()) {
148+ List <String > component = components .get (group );
149+ Collections .sort (component );
150+ component .add (0 , accountList .get (group ).get (0 ));
151+ mergedAccounts .add (component );
152+ }
153+
154+ return mergedAccounts ;
155+ }
156+
42157}
0 commit comments