[前端]_一起刷leetcode 947. 移除最多的同行或同列石头

557 阅读3分钟

大家好,我是挨打的阿木木,爱好算法的前端摸鱼老。最近会频繁给大家分享我刷算法题过程中的思路和心得。如果你也是想提高逼格的摸鱼老,欢迎关注我,一起学习。

题目

947. 移除最多的同行或同列石头

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
  • 不会有两块石头放在同一个坐标点上

思路

  1. 这道题目也是一道比较典型的并查集的题目,类似于我们之前做过的求省份数量的题目;
  2. 如果想像上次我们那种消除法进行消除,那么我们需要先遍历出坐标的最大值,然后建立好一个坐标数组;
  3. 这样子就可以像我们上次求解省份数量时候一样进行操作了,但是这道题目我们用并查集的解法来处理;
  4. 遍历整个石头堆,同时用两个map记录行和列,看看是否有同行同列出现过;
  5. 如果有的话,建立起两颗石头的关联关系;
  6. 再次遍历石头堆,判断有多少个有关联关系的,记录数量返回即可。

实现

/**
 * @param {number[][]} stones
 * @return {number}
 */
var removeStones = function(stones) {
    const n = stones.length;
    const uf = new UnionFind(n);

    let rowMap = new Map(), colMap = new Map();

    // 第一轮遍历,建立关系
    for (let i = 0; i < n; i++) {
        const [ row, col ] = stones[i];
        // 有同行的石头,标记到一起
        if (rowMap.has(row)) {
            uf.merge(i, rowMap.get(row));
        }

        // 有同列的石头,标记到一起
        if (colMap.has(col)) {
            uf.merge(i, colMap.get(col));
        }

        // 记录每一行每一列
        rowMap.set(row, i);
        colMap.set(col, i);
    }

    // 第二轮遍历,查找集合
    let result = 0;
    let set = new Set();

    // 如果有同行或者同列的,说明可删除,没有则新加
    for (let i = 0; i < n; i++) {
        let index = uf.find(i);
        if (set.has(index)) {
            result++;
        } else {
            set.add(index);
        }
    }

    return result;
};

class UnionFind {
  constructor(n) {
    // 一开始每个元素的父元素都是自己
    this.parent = new Array(n).fill(0).map((item, index) => index);
  }

  // 找到元素的父元素
  find(index) {
    return this.parent[index] = this.parent[index] === index ? index : this.find(this.parent[index]);
  }

  // 把index2的父元素设置为index1的父元素
  merge(index1, index2) {
    this.parent[this.find(index2)] = this.find(index1);
  }
}

看懂了的小伙伴可以点个关注、咱们下道题目见。如无意外以后文章都会以这种形式,有好的建议欢迎评论区留言。