并查集-移除最多的同行或同列石头

/**
 * n 块石头放置在二维平面中的一些整数坐标点上。每个坐标点上最多只能有一块石头。

如果一块石头的 同行或者同列 上有其他石头存在,那么就可以移除这块石头。

给你一个长度为 n 的数组 stones ,其中 stones[i] = [xi, yi] 表示第 i 块石头的位置,返回 可以移除的石子 的最大数量。
 */
//思路,并查集


public class test947 {
    //输入:stones = [[0,0],[0,1],[1,0],[1,2],[2,1],[2,2]]  5
    public static void main(String[] args) {
        int [][]stones={{0,0},{0,1},{1,0},{1,2},{2,1},{2,2}};
        int x=removeStones(stones);
    }
    public static int removeStones(int[][] stones) {
        if(stones.length==1){
            return 0;
        }
        int n=stones.length;
        int []parents=new int[stones.length];
        for(int i=0;i<n;i++){
            parents[i]=i;
        }
        int res=n;
        for(int i=0;i<n-1;i++){
            for(int j=i+1;j<n;j++){
                int a=find(parents, i);
                int b=find(parents, j);
                if(stones[i][0]==stones[j][0]||stones[i][1]==stones[j][1]){
                    if(a!=b){
                        parents[a]=b;
                        res--;
                    }
                }
            }
            
        }

        return n-res;
    }
    public static int find(int []parent,int i){
        if(parent[i]!=i){
            parent[i]=find(parent,parent[i]);
        }
        return parent[i];
    }
    
}

对于并查集,一般的模板是这样

// 未改进版本
class Djset {
public:
    vector<int> parent;  // 记录节点的根
    Djset(int n): parent(vector<int>(n)) {
        for (int i = 0; i < n; i++) parent[i] = i;
    }

    int find(int x) {
        if (x != parent[x]) return find(parent[x]);
        return parent[x];
    }

    void merge(int x, int y) {
        int rootx = find(x);
        int rooty = find(y);
     //这个merge的地方写merge逻辑,例如对于移出同行同列石头,就是如果行或者列相同,如果a!=b,也就是之前没合并,则合并,每次合并剩下的并查集个数-1
      //对于字符串交换排序,直接merge之后,遍历所有元素,将key取出来做 map的key,value用排序队列,每次拿出来每个key的从小到大
      //对于树的冗余连接,每根边的两个端点都判断是不是在同一并查集,不是就放在一起,是就直接return
parent[rooty]
= rootx; } };

要特别注意维护的parent里面是索引下标

原文地址:https://www.cnblogs.com/jieyi/p/14284668.html