n 块石头放置在二维平面中的一些整数坐标点上。每个坐标点上最多只能有一块石头。
如果一块石头的 同行或者同列 上有其他石头存在,那么就可以移除这块石头。
给你一个长度为 n 的数组 stones ,其中 stones[i] = [xi, yi] 表示第 i 块石头的位置,返回 可以移除的石子 的最大数量。
示例 1:
输入: 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] 不能移除,因为它没有与另一块石头同行/列。
示例 2:
输入: 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:
输入: stones = [[0,0]]
输出: 0
解释: [0,0] 是平面上唯一一块石头,所以不可以移除它。
提示:
1 <= stones.length <= 10000 <= xi, yi <= 104- 不会有两块石头放在同一个坐标点上
解题思路
本题其实就类似于消消乐游戏,当同行或同列有一个以上的石头,除了最后一个,都可以删除。
而且这个过程是可以递推的,所以我们可以把在同行或同列的石头放在一个集合,这样的一个集合中,只需要保留一块石头即可。
通过这种方式就可以获取到可移除的石头的数量。
因为过程中需要频繁对集合进行合并,以及获取石头所在集合,所以可以需要借助并查集解题。
如果你对 并查集 还不了解,可以看我这一篇文章 数据结构-并查集,文中介绍了并查集的概念、应用场景以及手写实现的全过程。
动画演示
代码实现
class UnionSet {
constructor(n){
// 初始化节点数量数组
this.size = Array(n).fill(1);
// 初始化集合列表,每一个节点为一个集合
this.list = Array(n);
for(let i = 0;i<n;i++){
this.list[i] = i;
}
}
// 递归获取元素所在集合根节点
find(x){
if(this.list[x] === x) return x;
// 获取到元素所在集合根节点
const root = this.find(this.list[x])
// 将当前节点挂载为根节点子节点,压缩路径
this.list[x] = root;
return root;
}
// 合并两个集合
merge(rootA,rootB){
// 如果 a 所在集合元素数量更多,将 b 所在集合合并到 a 所在集合
if(this.size[rootA]>this.size[rootB]){
this.list[rootB] = rootA;
this.size[rootA] += this.size[rootB]
}else{
// 反之将 a 所在集合合并到 b 所在集合
this.list[rootA] = rootB;
this.size[rootB] += this.size[rootA]
}
}
}
var removeStones = function(stones) {
// 获取石头数量
const len = stones.length,
// 创建并查集实例
unionset = new UnionSet(len);
// 初始化结果值
let res = 0;
for(let i = 0;i<len-1;i++){
for(let j = i+1;j<len;j++){
if(stones[i][0]===stones[j][0]||stones[i][1]===stones[j][1]){
// 获取两个元素所在集合的根节点
const rootA = unionset.find(i),rootB = unionset.find(j)
// 如果两个根节点不同,则进行合并,同时一次合并可以看做删除一个石头,结果值+1
if(rootA!==rootB){
res++;
unionset.merge(rootA,rootB)
}
}
}
}
// 返回结果值
return res;
};
至此我们就完成了 leetcode-947-移除最多的同行或同列石头
如有任何问题或建议,欢迎留言讨论!