移除最多的同行或同列石头
难度:
标签:
题目描述
代码结果
运行时间: 33 ms, 内存: 16.6 MB
/*
* 思路:
* 使用 Java Stream API 的同样逻辑来实现并查集。
* 我们可以使用 Arrays.stream 和 mapToObj 创建 Stone 对象的流,
* 然后使用 Collectors.toMap 将它们按索引进行收集,
* 最后使用同样的并查集算法来计算可移除的石头数量。
*/
import java.util.*;
import java.util.stream.*;
class Solution {
public int removeStones(int[][] stones) {
Map<Integer, int[]> stoneMap = IntStream.range(0, stones.length)
.boxed()
.collect(Collectors.toMap(i -> i, i -> stones[i]));
UnionFind uf = new UnionFind(stones.length);
stoneMap.forEach((i, stone1) -> {
stoneMap.forEach((j, stone2) -> {
if (i < j && (stone1[0] == stone2[0] || stone1[1] == stone2[1])) {
uf.union(i, j);
}
});
});
return stones.length - uf.getCount();
}
class UnionFind {
private int[] parent;
private int count;
public UnionFind(int n) {
parent = new int[n];
count = n;
IntStream.range(0, n).forEach(i -> parent[i] = i);
}
public int find(int x) {
if (parent[x] != x) {
parent[x] = find(parent[x]);
}
return parent[x];
}
public void union(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY) {
parent[rootX] = rootY;
count--;
}
}
public int getCount() {
return count;
}
}
}
解释
方法:
这道题目可以通过并查集的数据结构来解决。每块石头可以通过其行和列来进行连接,如果两块石头处于同一行或同一列,它们可以属于同一个连通分量。并查集可以帮助我们维护这些连通分量的信息。具体步骤如下:1. 初始化并查集。2. 遍历每块石头,将其行和列视为连接点,如果当前行或列已经有石头,就将当前石头与之前的石头进行合并。3. 最后,连通分量的数量即为不能被移除的石头数量,其余的石头都可以被移除。
时间复杂度:
O(n \alpha(n))
空间复杂度:
O(n)
代码细节讲解
🦆
在并查集中,为什么将行和列的索引作为连接点,而不是直接使用石头的索引?
▷🦆
并查集初始化时,为什么要设置p的长度为n+1而不是n?
▷🦆
在遍历stones时,为什么要从索引1开始而不是0?这对并查集的操作有什么影响吗?
▷🦆
在算法最后,通过计算连通分量的数量来确定不能被移除的石头数量,这里的逻辑是如何确保每个连通分量中至少有一块石头不能被移除的?
▷