// DFS
void dfs(vector<vector<int> >& index, unordered_set<int>& visited, int i) {
if (visited.count(i)) return;
visited.insert(i);
for (int j : index[i]) {
if (visited.count(j)) continue;
dfs(index, visited, j);
}
}
int removeStones(vector<vector<int>>& stones) {
// Trick to differentiate row id and col id
const int k = 10000;
vector<vector<int> > index(2 * k);
for (const vector<int>& stone : stones) {
index[stone[0]].push_back(stone[1] + k);
index[stone[1] + k].push_back(stone[0]);
}
unordered_set<int> visited;
int islands = 0;
for (const vector<int>& stone : stones) {
if (visited.count(stone[0])) continue;
++islands;
dfs(index, visited, stone[0]);
dfs(index, visited, stone[1] + k);
}
return stones.size() - islands;
}
// Union-Find
int find(vector<int>& roots, int i) {
return roots[i] == i ? i : roots[i] = find(roots, roots[i]);
}
void uni(vector<int>& roots, int x, int y) {
x = find(roots, x), y = find(roots, y);
if (x != y) {
roots[y] = x;
}
}
int removeStones(vector<vector<int>>& stones) {
const int k = 10000;
vector<int> roots(2 * k);
for (int i = 0; i < roots.size(); ++i) roots[i] = i;
for (const vector<int>& stone : stones) {
uni(roots, stone[0], stone[1] + k);
}
unordered_set<int> islands;
for (const vector<int>& stone : stones) {
islands.insert(find(roots, stone[0]));
}
return stones.size() - islands.size();
}
// Union-Find
int find(vector<int>& roots, int i) {
return roots[i] == i ? i : roots[i] = find(roots, roots[i]);
}
void connect(vector<int>& roots, int i, int j) {
roots[find(roots, j)] = find(roots, i);
}
int removeStones(vector<vector<int>>& stones) {
const int n = stones.size();
vector<int> roots(n);
for (int i = 0; i < n; ++i) roots[i] = i;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < i; ++j) {
if (stones[i][0] == stones[j][0] || stones[i][1] == stones[j][1]) {
connect(roots, i, j);
}
}
}
int cnt = 0;
for (int i = 0; i < n; ++i) {
if (roots[i] == i) ++cnt;
}
return n - cnt;
}