并查集(947. 移除最多的同行或同列石头)

437 阅读2分钟

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

题目介绍

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

思路分析

题意分析

image.png 自己陷入过的误区

能够连通的只需要保留一个,我首先想到的是深度或者广度遍历,从一个点出发,遍历这个点能触及到的所有点,感觉也非常合理

但是该题的陷阱也在于此,题目对于stones.length,仅限制在1-1000中,而横纵坐标却在10000范围内,如果我们构建一个图,需要的是10000*10000的内存,对于仅仅不到1000的数据,也太稀疏了

如果不使用矩阵,深度或者广度遍历也很困难,难道构建两层for(int i=0;i<10000;i++)这样去遍历吗。获取我们可以采用邻接矩阵

思路一 广度优先遍历

最后我的思路是这样的

image.png 其中横坐标纵坐标链表的实现可以使用HashMap<Interger,HashSet< Interger >>进行,其中的set随着不断的访问还能进行删除,减少重复访问

思路二 并查集

这个就很符合题意了,创建一个一维数组存放各个石头的父亲节点

然后考虑三种情况 创建两个HashMap分别存储行对应的点和列对应的点

  1. 该石头的行列都没有出现过,那么是新石头,自己创建一个家族
  2. 该石头的行出现过,那把此列指像自己,然后通过行找到那个点,并通过getFather找到最终节点,把自己并上去
  3. 如果该石头的行列都出现,同2先查到行列所属的最终节点是不是一个,是一个那就没事了,如果不是一个就合并两大家族
class Solution {
    int[] father;
    public int removeStones(int[][] stones) {
        father=new int[stones.length];
        for (int i = 0; i < father.length; i++) {
            father[i]=-1;
        }
        HashMap<Integer,Integer>row=new HashMap<>();
        HashMap<Integer,Integer>line=new HashMap<>();
        
        for (int i = 0; i < stones.length; i++) {
            if(row.containsKey(stones[i][0])&&line.containsKey(stones[i][1])){
                int num1=getFather(row.get(stones[i][0]));
                int num2=getFather(line.get(stones[i][1]));
                
                if(num1!=num2){
                    father[num1]=num2;
                }
                father[i]=num2;
            }else if(row.containsKey(stones[i][0])){
                int num1=getFather(row.get(stones[i][0]));
                father[i]=num1;
                line.put(stones[i][1],i);
            }else if(line.containsKey(stones[i][1])){
                int num2=getFather(line.get(stones[i][1]));
                father[i]=num2;
                row.put(stones[i][0],i);
            }else {
                row.put(stones[i][0],i);
                line.put(stones[i][1],i);
            }
        }
        int count=0;
         //System.out.println(Arrays.toString(father));
          //System.out.println(row);
          //System.out.println(line);
        for (int i = 0; i < father.length; i++) {
            if(father[i]!=-1)count++;
        }
        return count;
        
    }
    public int getFather(Integer num){
        if(father[num]==-1)return num;
        return getFather(father[num]);
    }

}