leetcode-并查集-P547省份数量+P685冗余连接

public class P547省份数量 {

    private class UnionFind{
        int count;
        int[] parent;

        public UnionFind(int n){
            this.count=n;
            this.parent=new int[n];
            for (int i = 0; i < n; i++) {
                parent[i]=i;
            }
        }

        public int find(int i){
            while(parent[i]!=i){
                i=parent[i];
            }
            return i;
        }

        public void union(int q,int p){
            int qRoot=find(q);
            int pRoot=find(p);
            if (qRoot==pRoot){
                return;
            }
            parent[qRoot]=pRoot;
            count--;
        }

    }

    public int findCircleNum(int[][] isConnected) {
        int n = isConnected.length;
        UnionFind unionFind = new UnionFind(n);
        for (int i = 0; i < n; i++) {
            // 优化不用走相同的i j 的访问
            for (int j = i+1; j < n; j++) {
                if (isConnected[i][j]==1){
                    unionFind.union(i,j);
                }
            }
        }
        return unionFind.count;
    }

}
public class P684冗余连接 {

    /*
    并查集:方法一:并查集
    树是一个连通且无环的无向图,在树中多了一条附加的边之后就会出现环,因此附加的边即为导致环出现的边
    可以通过并查集寻找附加的边。初始时,每个节点都属于不同的连通分量。遍历每一条边,判断这条边连接的两个顶点是否属于相同的连通分量
    如果两个顶点属于不同的连通分量,则说明在遍历到当前的边之前,这两个顶点之间不连通,因此当前的边不会导致环出现,合并这两个顶点的连通分量
    如果两个顶点属于相同的连通分量,则说明在遍历到当前的边之前,这两个顶点之间已经连通,因此当前的边导致环出现,为附加的边,将当前的边作为答案返回
     */
    public int[] findRedundantConnection(int[][] edges) {
        int n = edges.length;
        UnionFind unionFind = new UnionFind(n);
        for (int[] edge : edges) {
            if (unionFind.find(edge[0]) != unionFind.find(edge[1])) {
                unionFind.union(edge[0], edge[1]);
            } else {
                // 此处也是最后出现的边,因为前面的是建立连通图,当找到这条造成环的边时就是最后的边
                return edge;
            }
        }
        return new int[0];
    }
    public class UnionFind {
        // 记录父节点,每个联通节点通过这个连接
        private int[] parent;
        // 连通分量,总共有多少个是连通的
        private int count;


        /* 构造函数,n 为图的节点总数 */
        public UnionFind(int n) {
            // 一开始互不连通
            this.count = n;
            // 父节点指针初始指向自己
            // 因为此题特殊性,数组是1~n 所以数父节点初始化从1开始
            parent = new int[n+1];
            for (int i = 1; i <= n; i++) {
                parent[i] = i;
            }
        }

        public void union(int p, int q) {
            int rootP = find(p);
            int rootQ = find(q);
            // 如果是同一个连通节点
            if (rootP == rootQ) {
                return;
            }
            // 将两个区域合并为一区域
            parent[rootP] = rootQ;
            // parent[rootQ] = rootP 也一样
            count--; // 两个分量合二为一
        }
        /* 返回某个节点 x 的根节点 */
        public int find(int x) {
            // 循环找根节点是 parent[x] == x
            // 也可以递归
            while (parent[x] != x) {
                x = parent[x];
            }
            return x;
        }

        /* 返回当前的连通分量个数 */
        public int count() {
            return count;
        }

        // 这样,如果节点p和q连通的话,它们一定拥有相同的根节点:
        public boolean connected(int p, int q) {
            int rootP = find(p);
            int rootQ = find(q);
            return rootP == rootQ;
        }

        /* 返回某个节点 x 的根节点 */
        private int findRecusion(int x) {
            // 递归找根节点是 parent[x] == x
            if (parent[x]==x){
                return x;
            }
            return parent[x]=find(parent[x]);
        }
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值