[C++] Union Find || Bitset 
IntuitionThe question states that there are n nodes 0 to n-1.
Since There exists between node i to j only if intersect(properties[i], properties[j]) >= k, where
# Intuition
<!-- Describe your first thoughts on how to solve this problem. -->
The question states that there are n nodes `0` to `n-1`.
Since There exists between node `i` to `j` only if `intersect(properties[i], properties[j]) >= k`, where `intersect(a, b) that returns the number of distinct integers common to both arrays a and b`.
The key thing is to compute `intersection` optimally, 

    we can make use of bitset or any similar thing to do the same optimally
    represent presence of element in bitset and make use of `bitwise and`(&) to intersect those two

We can either use Depth-first, Breath-first search or Union Find/ DisJoint set to find the number of components.

# Approach
<!-- Describe your approach to solving the problem. -->
- Use a vector of bitset<100> 
- For each Property
    -  Mark presence of each element in that property in the respective bitset.
- Declare a DisJointset
- for i from 0 until n
    - for j from i+1 until n
        -  if (countSetBits(hash[i] & hash[j]) >= k) connect / union node i and j
- return the number of components
# Complexity
- Time complexity: $$O(n^2)$$
<!-- Add your time complexity here, e.g. $$O(n)$$ -->

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

# Code
```cpp []
class DisJointSet {
    int nC;
    vector<int> parent;
public:
    vector<int> size;
    DisJointSet(int n) {
        nC = n;
        parent.resize(n);
        size.resize(n, 1);
        iota(parent.begin(), parent.end(), 0);
    }

    int find(int node) {
        if(node == parent[node]) return node;
        return parent[node] = find(parent[node]);
    }

    void unionSet(int u, int v) {
        int parU = find(u), parV = find(v);

        if(parU == parV) return ;

        if(size[parU] < size[parV]) {
            parent[parU] = parent[parV];
            size[parV] += size[parU];
        } else {
            parent[parV] = parent[parU];
            size[parU] += size[parV];
        }

        nC--;
    }

    int getNC() const { return nC; }
};

class Solution {
public:
    int numberOfComponents(vector<vector<int>>& properties, int k) {
        int n = properties.size(), m = properties[0].size();
        DisJointSet ds(n);

        bitset<100> intersection;
        vector<bitset<100>> hash(n);
        for(int i=0; i<n; i++) 
            for(int j=0; j<m; j++)
                hash[i].set(properties[i][j] - 1);

        for(int i=0; i<n; i++) {
            for(int j=i+1; j<n; j++) {
                intersection = hash[i] & hash[j];
                if(intersection.count() >= k) ds.unionSet(i, j);
            }
        }

        return ds.getNC();
    }
};
```
['Hash Table', 'Bit Manipulation', 'Union Find', 'C++']