Skip to content

Commit f7e29f6

Browse files
committed
final version of Merge Accounts using Disjoint set
1 parent ebd7763 commit f7e29f6

File tree

1 file changed

+118
-3
lines changed

1 file changed

+118
-3
lines changed
Lines changed: 118 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,34 @@
11
package 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+
322
public 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

Comments
 (0)