路飞]_leetcode-947-移除最多的同行或同列石头

简介: leetcode-947-移除最多的同行或同列石头

网络异常,图片无法展示
|


[题目地址][B站地址]


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 <= 1000
  • 0 <= 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-移除最多的同行或同列石头


如有任何问题或建议,欢迎留言讨论!

相关文章
|
1月前
|
C++
【PTA】L1-019 谁先倒 (C++)
【PTA】L1-019 谁先倒 (C++)
41 0
【PTA】L1-019 谁先倒 (C++)
|
存储 C++
【PAT甲级 - C++题解】1036 Boys vs Girls
【PAT甲级 - C++题解】1036 Boys vs Girls
57 0
【CCCC】L2-029 特立独行的幸福 (25分),模拟题,set用法
【CCCC】L2-029 特立独行的幸福 (25分),模拟题,set用法
144 0
PTA 谁先倒
L1-019 谁先倒 分数 15 划拳是古老中国酒文化的一个有趣的组成部分。酒桌上两人划拳的方法为:每人口中喊出一个数字,同时用手比划出一个数字。如果谁比划出的数字正好等于两人喊出的数字之和,谁就输了,输家罚一杯酒。两人同赢或两人同输则继续下一轮,直到唯一的赢家出现。 下面给出甲、乙两人的酒量(最多能喝多少杯不倒)和划拳记录,请你判断两个人谁先倒。
149 0