并查集

关于路径压缩

//隔代压缩
int find(int x) {
    while (x != parent[x]) {
        x = parent[x];
        parent[x] = parent[parent[x]];
    }
    return parent[x];
}

//完全压缩,一般用于带权图,因为要遍历边
int find(int x) {
    if (x != parent[x]) {
        //int mark = parent[x];
        parent[x] = find[parent[x]];
        //weight[x] += weight[mark];
    }
    return parent[x]; //注意这里递归的是parent[x],x的没有变的
}

 

关于时间复杂度

 

朋友圈 题目 解析

class Solution {

    class UF {
        private int count;
        private int parent[]; //它的父节点
        private int size[]; //以自己为根节点的树有多少节点

        public UF(int n) {
            this.count = n;
            parent = new int[n];
            size = new int[n];
            //初始化的时候自己的父节点指向自己
            for (int i = 0; i < n; i++) {
                parent[i] = i;
                size[i] = 1; 
            }
        }

        //找到x的根节点
        private int find(int x) {
            while (x != parent[x]) {
                //路径压缩,画个图就明白了。就是和自己的父亲做兄弟。
                parent[x] = parent[parent[x]];
                x = parent[x];
            }
            return x;
        }


        //连接
        public void union(int p, int q) {
            //找到各自的根节点。
            int rootP = find(p); //你看,每次find的时候都进行了路径压缩。
            int rootQ = find(q);
            if (rootP == rootQ) return;

            //把小的树接到大的树上面
            if (size[rootQ] > size[rootP]) {
                parent[rootP] = rootQ;
                size[rootQ] += size[rootP];
            } else {
                parent[rootQ] = rootP;
                size[rootP] += size[rootQ];
            }
            count--;
        }

        public boolean connect(int p, int q) {
            return find(p) == find(q);
        }

        public int count() {
            return count;
        }
    }

    public int findCircleNum(int[][] M) {
        int N = M.length;
        UF uf = new UF(N);
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                if (M[i][j] == 1) {
                    uf.union(i, j);
                }
            }
        }
        return uf.count();
    }
}

 深度优先

class Solution {
    public int findCircleNum(int[][] M) {
        int N = M.length, count = 0;
        boolean[] V = new boolean[N];
        for (int i = 0; i < N; i++) {
            if (!V[i]) {
                count++;
                dfs(V, M, i);
            }
        }
        return count;
    }

    private void dfs(boolean[] V, int[][]M, int i) {
        for (int j = 0; j < M.length; j++) {
            if (M[i][j] == 1 && !V[j]) {
                V[j] = true;
                dfs(V, M, j);
            }
        }
    }
}

广度优先

class Solution {
    public int findCircleNum(int[][] M) {
        int N = M.length, count = 0;
        Queue<Integer> queue = new LinkedList<>();
        boolean[] V = new boolean[N];
        for (int i = 0; i < N; i++) {
            if (!V[i]) {
                queue.offer(i);
                count++;
                while (!queue.isEmpty()){
                    int k = queue.poll();
                    V[k] = true;
                    for (int j = 0; j < N; j++) {
                        if (M[k][j] == 1 && !V[j]) {
                            queue.offer(j);
                        } 
                    }
                }
            }
        }
        return count;
    }
}

 

连通网络的操作次数

模板一放,直接ac

class Solution {

    class UF {

        private int[] parent;
        private int[] size;

        UF(int n){
            parent = new int[n];
            size = new int[n];
            for (int i = 0; i < n; i++) {
                parent[i] = i;
                size[i] = 1;
            }
        }

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

        public void union(int p, int q) {
            int rp = find(p), rq = find(q);
            if (p == q) return;
            if (size[rp] > size[rq]) {
                parent[rq] = rp;
                size[rp] += size[rq];
            } else {
                parent[rp] = rq;
                size[rq] += size[rp];
            }
        } 

        public int size(int x) {
            return size[x];
        }
    }

    public int minMalwareSpread(int[][] graph, int[] initial) {
        int n = graph.length;
        UF uf = new UF(n);
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                if (graph[i][j] == 1) {
                    uf.union(i, j);
                }
            }
        }

        int[] count = new int[n];
        for (int x : initial) {
            count[uf.find(x)]++;
        }

        int res = -1, max = 0;
        for (int x : initial) {
            int rx = uf.find(x);
            if (count[rx] == 1) {
                int sx = uf.size(rx);
                if (sx > max) {
                    max = sx;
                    res = x;
                } else if (sx == max && x < res) {
                    res = x;
                }
            }
        }

        if (res == -1) {
            res = Integer.MAX_VALUE;
            for (int x : initial) {
                res = Math.min(res, x);
            }
        }

        return res;
    }
}

 

尽量减少恶意软件的传播

先用并查集构造出树。如果一棵树里只有一个坏节点,那么这个节点可以去掉。所以找出只有一个坏节点并且节点数量最多的树。

class Solution {

    class UF {

        private int[] parent;
        private int[] size;

        UF(int n){
            parent = new int[n];
            size = new int[n];
            for (int i = 0; i < n; i++) {
                parent[i] = i;
                size[i] = 1;
            }
        }

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

        public void union(int p, int q) {
            int rp = find(p), rq = find(q);
            if (p == q) return;
            if (size[rp] > size[rq]) {
                parent[rq] = rp;
                size[rp] += size[rq];
            } else {
                parent[rp] = rq;
                size[rq] += size[rp];
            }
        } 

        public int size(int x) {
            return size[x];
        }
    }

    public int minMalwareSpread(int[][] graph, int[] initial) {
        int n = graph.length;
        UF uf = new UF(n);
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                if (graph[i][j] == 1) {
                    uf.union(i, j);
                }
            }
        }

        int[] count = new int[n];
        for (int x : initial) {
            count[uf.find(x)]++;
        }

        int res = -1, max = 0;
        for (int x : initial) {
            int rx = uf.find(x);
            if (count[rx] == 1) {
                int sx = uf.size(rx);
                if (sx > max) {
                    max = sx;
                    res = x;
                } else if (sx == max && x < res) {
                    res = x;
                }
            }
        }

        if (res == -1) {
            res = Integer.MAX_VALUE;
            for (int x : initial) {
                res = Math.min(res, x);
            }
        }

        return res;
    }
}

 

除法求值

带权并查集

class Solution {
    public double[] calcEquation(List<List<String>> equations, double[] values, List<List<String>> queries) {

        //字符串到数字的映射,这样就可以放在数组里了
        Map<String, Integer>map = new HashMap<>();

        double[] res = new double[queries.size()];
        UF uf = new UF(2 * values.length);
        int id = 0;
        for (int i = 0; i < values.length; i++) {
            String a = equations.get(i).get(0);
            String b = equations.get(i).get(1);
            if (!map.containsKey(a)) {
                map.put(a, id++);
            }
            if (!map.containsKey(b)) {
                map.put(b, id++);
            }
            uf.union(map.get(a), map.get(b), values[i]);
            //uf.union(map.get(b), map.get(a), 1 / values[i]);
            //并不用反向再连一遍,因为并查集里面已经连接了a和b。在uf.get里得到正确的结果。
        }

        for (int i = 0; i < queries.size(); i++) {
            String a = queries.get(i).get(0);
            String b = queries.get(i).get(1);
            if (!map.containsKey(a) || !map.containsKey(b)) {
                res[i] = -1.0;
            }else {
                res[i] = uf.get(map.get(a), map.get(b));
            }
        }
        return res;
    }

    class UF {
        private int[] parent;  //父节点
        private double[] weight; //带权,指该节点到其父节点的权值

        public UF(int n) {
            parent = new int[n];
            weight = new double[n];
            for (int i = 0; i < n; i++) {
                parent[i] = i;
                weight[i] = 1.0;
            }
        }

        private int find(int x) {
            //递归是parent[x], x还是那个x
            if (x != parent[x]) {
                int mark = parent[x];
                parent[x] = find(parent[x]);
                weight[x] *= weight[mark]; 
            }
            return parent[x];
        }

        public void union(int a, int b, double value) {
            int rootA = find(a);
            int rootB = find(b);
            if (rootA == rootB) return;
            parent[rootA] = rootB;
            weight[rootA] = value * weight[b] / weight[a];
        }

        public double get(int a, int b) {
            if (find(a) != find(b)) return -1.0;
            return weight[a] / weight[b];
        } 
    }
}

 

posted @ 2020-12-14 19:13  CPJ31415  阅读(63)  评论(0)    收藏  举报