题目:n 块石头放置在二维平面中的一些整数坐标点上。每个坐标点上最多只能有一块石头。如果一块石头的 同行或者同列 上有其他石头存在,那么就可以移除这块石头。给你一个长度为 n 的数组 stones ,其中 stones[i] = [xi, yi] 表示第 i 块石头的位置,返回可以移除的石子 的最大数量。
提示:1 <= stones.length <= 1000;0 <= xi, yi <= 104
;不会有两块石头放在同一个坐标点上。
//示例1
输入:stones = [[0,0],[0,1],[1,0],[1,2],[2,1],[2,2]]
输出:5
//示例2
输入:stones = [[0,0],[0,2],[1,1],[2,0],[2,2]]
输出:3
//示例3
输入:stones = [[0,0]]
输出:0
分析:同行同列上只允许一块石头,可以转化为连通量的问题,所有横坐标为 x
的石头和所有纵坐标为 y
的石头都属于同一个连通分量。而最多可移除的石头个数 = 所有石头的个数 - 连通分量的个数。需注意的是,横坐标和纵坐标有可能相等,我们需要对其进行区分,根据提示横纵坐标在 [0, 10000]区间中,可以将其中一个映射到另一个与 [0, 10000] 不重合的区间,这里选择将横坐标全部加上 10001。在并查集中,我们需要维护连通分量的个数,新创建顶点的时候连通分量加 1;合并不在同一个连通分量中的两个并查集的时候,连通分量减 1。
public int removeStones(int[][] stones) {
int len = stones.length;
Unionfind uf = new Unionfind();
for(int i = 0;i < len;i++){
uf.union(stones[i][0] + 10001,stones[i][1]);
}
return len - uf.getCount();
}
class Unionfind{
HashMap<Integer,Integer> map;//value:父节点
private int count;
Unionfind(){
map = new HashMap<>();
count = 0;
}
int getCount(){
return count;
}
void union(int x,int y){
int rootX = find(x);
int rootY = find(y);
if(rootX == rootY)
return;
map.put(rootX,rootY);
count--;//合并,连通分量数减一
}
private int find(int x) {
if(! map.containsKey(x)){
map.put(x,x);
count++;//并查集中新加入一个结点,结点的父亲结点是它自己,所以连通分量的总数 +1
}
if(x != map.get(x)){
map.put(x,find(map.get(x)));
}
return map.get(x);
}
}