1.Description
n 块石头放置在二维平面中的一些整数坐标点上。每个坐标点上最多只能有一块石头。
如果一块石头的 同行或者同列 上有其他石头存在,那么就可以移除这块石头。
给你一个长度为 n 的数组 stones ,其中 stones[i] = [xi, yi] 表示第 i 块石头的位置,返回 可以移除的石子 的最大数量。
2.Example
输入:stones = [[0,0],[0,1],[1,0],[1,2],[2,1],[2,2]]
输出:5
解释:一种移除 5 块石头的方法如下所示:
1. 移除石头 [2,2] ,因为它和 [2,1] 同行。
2. 移除石头 [2,1] ,因为它和 [0,1] 同列。
3. 移除石头 [1,2] ,因为它和 [1,0] 同行。
4. 移除石头 [1,0] ,因为它和 [0,0] 同列。
5. 移除石头 [0,1] ,因为它和 [0,0] 同行。
石头 [0,0] 不能移除,因为它没有与另一块石头同行/列。
输入:stones = [[0,0],[0,2],[1,1],[2,0],[2,2]]
输出:3
解释:一种移除 3 块石头的方法如下所示:
1. 移除石头 [2,2] ,因为它和 [2,0] 同行。
2. 移除石头 [2,0] ,因为它和 [0,0] 同列。
3. 移除石头 [0,2] ,因为它和 [0,0] 同行。
石头 [0,0] 和 [1,1] 不能移除,因为它们没有与另一块石头同行/列。
3.Solution
一定可以把一个连通图里的所有顶点根据这个规则删到只剩下一个顶点。最多可以移除的石头的个数 = 所有石头的个数 - 连通分量的个数。
使用了并查集,结合题解,这里主要解释一下代码中每一步的意思。(注释)
使用Map
**:这里的find和union是将所有连通的节点的x坐标和y坐标放到一个并查集里
import java.util.HashMap;
import java.util.Map;
public class Solution {
public int removeStones(int[][] stones) {
UnionFind unionFind = new UnionFind();
for (int[] stone : stones) {
// 下面这三种写法任选其一
// unionFind.union(~stone[0], stone[1]);
// unionFind.union(stone[0] - 10001, stone[1]);
unionFind.union(stone[0] + 10001, stone[1]);
//因为x,y坐标取值范围是0到10000,而在map中需要使用
//get(key)的函数,key的值可能为x也可能为y,因此需确保x和y的值不一样。
}
return stones.length - unionFind.getCount();
}
private class UnionFind {
private Map<Integer, Integer> parent;
private int count;//连通分量的数量
public UnionFind() {
this.parent = new HashMap<>();
this.count = 0;
}
public int getCount() {
return count;
}
public int find(int x) {
if (!parent.containsKey(x)) {
parent.put(x, x);
// 并查集集中新加入一个结点,结点的父亲结点是它自己
//所以连通分量的总数 +1
count++;
}
if (x != parent.get(x)) {
parent.put(x, find(parent.get(x)));
//找到根节点,因为put会刷新,所以递归结束后结点都是直接指向根节点,
//也就是说并查集只有两层,find递归一次就找到根节点。
}
return parent.get(x);
}
public void union(int x, int y) {//因为将x和y的值平等的看做集合里的点了,所以可以直接合并了
int rootX = find(x);
int rootY = find(y);
if (rootX == rootY) {//根节点相同,说明在同一个集合里了
return;
}
parent.put(rootX, rootY);//将X根节点接到Y根节点后
// 两个连通分量合并成为一个,连通分量的总数 -1
count--;
}
}
}
使用数组
class Solution {
int p[] = new int[20009];
public int removeStones(int[][] stones) {
int res = 0;
for(int i=0;i<p.length;i++) {
p[i] = i;
}
for(int i=0;i<stones.length;i++) {
union(stones[i][0],stones[i][1]+10000);
}
Set<Integer> set = new HashSet<>();
for(int i=0;i<stones.length;i++) {
set.add(find(stones[i][0]));
}
return stones.length-set.size();
}
private int find(int i) {
// TODO Auto-generated method stub
if(p[i]!=i) {
p[i] = find(p[i]);
}
return p[i];
}
private void union(int i, int j) {
// TODO Auto-generated method stub
p[find(i)] = find(j);
}
}