Union Find || Disjoint Set || O(n^2*m) || Faster than 99% || Clean Java Code
Complexity
Time complexity: O(n2∗m)

Space complexity: O(n∗m)
Code
# Complexity
- Time complexity: $$O(n^2*m)$$
<!-- Add your time complexity here, e.g. $$O(n)$$ -->

- Space complexity: $$O(n*m)$$
<!-- Add your space complexity here, e.g. $$O(n)$$ -->

# Code
```java []
class DisjointSet {
    private final int[] root;
    private final int[] rank;
    private int count;

    public DisjointSet(int size) {
        root = new int[size];
        rank = new int[size];
        for (int i = 0; i < size; i++) {
            root[i] = i;
            rank[i] = 1;
        }
    }

    public int getCount() {
        Set<Integer> roots = new HashSet<>();
        for (int i = 0; i < root.length; i++) {
            roots.add(find(i));
        }
        return roots.size();
    }

    public void union(int vertex1, int vertex2) {
        int root1 = find(vertex1);
        int root2 = find(vertex2);
        if (root1 != root2) {
            if (rank[root1] > rank[root2]) {
                root[root2] = root1;
            } else if (rank[root2] > rank[root1]) {
                root[root1] = root2;
            } else {
                root[root2] = root1;
                rank[root1]++;
            }
        }
    }

    private int find(int vertex) {
        if (root[vertex] == vertex) return vertex;
        return root[vertex] = find(root[vertex]);
    }
}

class Solution {
    public int numberOfComponents(int[][] properties, int k) {
        DisjointSet disjointSet = new DisjointSet(properties.length);
        for (int i = 0; i < properties.length; i++) {
            boolean[] distinct = new boolean[101];
            for (int l = 0; l < properties[i].length; l++) {
                distinct[properties[i][l]] = true;
            }
            for (int j = i + 1; j < properties.length; j++) {
                long intersect = intersect(distinct, properties[j]);
                if (intersect >= k) {
                    disjointSet.union(i, j);
                }
            }
        }
        return disjointSet.getCount();
    }

    private long intersect(boolean[] prop1, int[] prop2) {
        long count = 0;
        boolean[] counted = new boolean[101];
        for (int p : prop2) {
            if (prop1[p] && !counted[p]) {
                counted[p] = true;
                count++;
            }
        }
        return count;
    }
}
```
['Array', 'Union Find', 'Graph', 'Java']