class Solution {
public int countCompleteComponents(int n, int[][] edges) {
UnionFind uf = new UnionFind(n);
// Perform union operations for all edges
for (int[] edge : edges) {
uf.union(edge[0], edge[1]);
}
Map<Integer, Set<Integer>> componentNodes = new HashMap<>();
Map<Integer, Integer> componentEdges = new HashMap<>();
// Count nodes in each component
for (int i = 0; i < n; i++) {
int root = uf.find(i);
componentNodes.putIfAbsent(root, new HashSet<>());
componentNodes.get(root).add(i);
}
// Count edges in each component
for (int[] edge : edges) {
int root = uf.find(edge[0]);
componentEdges.put(root, componentEdges.getOrDefault(root, 0) + 1);
}
int completeComponentsCount = 0;
// Check for complete components
for (Map.Entry<Integer, Set<Integer>> entry : componentNodes.entrySet()) {
int nodeCount = entry.getValue().size();
int edgeCount = componentEdges.getOrDefault(entry.getKey(), 0);
if (edgeCount == nodeCount * (nodeCount - 1) / 2) {
completeComponentsCount += 1;
}
}
return completeComponentsCount;
}
class UnionFind{
int[] rank;
int[] root;
public UnionFind(int s){
rank = new int[s];
root = new int[s];
Arrays.fill(rank, 1);
for(int i = 0; i < s; i++){
root[i] = i;
}
}
public void union(int A, int B){
int rootA = find(A);
int rootB = find(B);
if(rank[rootA] > rank[rootB]){
root[rootB] = rootA;
}else if(rank[rootA] < rank[rootB]){
root[rootA] = rootB;
}else{
root[rootB] = rootA;
rank[rootA] += 1;
}
}
public int find(int node){
if(root[node] == node){
return node;
}else{
return root[node] = find(root[node]);
}
}
public int[] nodes(){
return root;
}
}
}