2021-01-15 947.移除最多的同行或同列石头 [并查集]

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

思路一:并查集

其实这道题看似花里胡哨,实际上能移除的石头个数就是石头总个数减去属于同一类别(我们把处于同一列同一行能联通的石头放在一类)的石头个数。因为一坨互相联通的石头之间总可以移除到只剩下一块。
这个想法的证明可以倒过来想,如果只剩一块,根据我们分类的定义,只要没有达到该类别总个数,一定存在同一类的元素与其相连(处于同一行或者同一列),因此可以添加到两块,以此类推,就可以还原到最初状态。
又因为能加一块就一定能删一块,因此,我们证明了一坨互相联通的石头之间总可以移除到只剩下一块。

class Solution {
    
    
    public int removeStones(int[][] stones) {
    
    
        // 第一步,初始化每一块石头,这里由题目假设知,不会由两块石头放在同一个位置上
        Stone[] st = new Stone[stones.length];
        for(int i=0;i<stones.length;i++){
    
    
            st[i] = new Stone(stones[i]);
            // System.out.println(st[i].index);
        }

        // 第二步:将同行同列的石头合并在一起
        UnionFind uf = new UnionFind(st.length);
        for(int i=0;i<st.length;i++)
            for(int j=i+1;j<st.length;j++){
    
    
                if(st[i].sameline(st[j])){
    
    
                    uf.union(i,j);
                    //System.out.println(i+" "+j);
                }
            }
        // 因为有多少个类别就能剩下多少个元素
        return st.length-uf.count();
    }
}

class Stone{
    
    
    int[] coord;
    int index;
    static int total=0; // 用来记录石头总数

    public Stone(int[] coord){
    
    
        this.coord = coord;
        this.index = index;
        
        this.index = Stone.total++;
        // System.out.println(this.index);
        // System.out.println(Stone.total);
    }
    
    public boolean sameline(Stone other){
    
    
        return this.coord[0]==other.coord[0] || this.coord[1]==other.coord[1];
    }

}

class UnionFind{
    
    
    int[] elements;
    int[] rank;

    public UnionFind(int N){
    
    
        this.rank = new int[N];
        this.elements = new int[N];
        for(int i=0;i<N;i++)
            this.elements[i]=i;
    }
    
    public int find(int i){
    
    
        if(elements[i]==i)
            return i;
        else{
    
    
            elements[i]=find(elements[i]);
            return elements[i];
        }
    }

    public void union(int i,int j){
    
    
        int parenti = find(i);
        int parentj = find(j);
        if(rank[parenti]<rank[parentj])
            elements[parenti]=parentj;
        else if(rank[parenti]>rank[parentj])
            elements[parentj]=parenti;
        else{
    
    
            elements[parentj]=parenti;
            rank[parenti]++;
        }

    }

    // 统计类别数量
    public int count(){
    
    
        int res=0;
        for(int i=0;i<elements.length;i++)
            if(elements[i]==i)
                res++;
        return res;
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_44495738/article/details/112685817