并查集的应用

101 阅读1分钟

并查集算法应用

通过Union对象来通过联通区域的个数

应用案例:leetcode-cn.com/problems/nu…


    class Union{
        int count;
        int[] rank;
        int[] parent;

        public Union(char[][] grid){
            count = 0;
            int row = grid.length;
            int col = grid[0].length;
            rank = new int[row*col];
            parent = new int[row*col];
            for(int i=0; i<row; i++){
                for(int j=0; j<col; j++){
                    if(grid[i][j] == '1'){
                        parent[i * col + j] = i * col + j;
                        count++;
                    }
                    rank[i * col + j] = 0;
                }
            }
        }
        public void union(int i, int j){
            int ri = find(i);
            int rj = find(j);
            if(ri!=rj){
                if(rank[ri]>rank[rj]){
                    parent[rj] = ri;
                }else if(rank[ri]<rank[rj]){
                    parent[ri] = rj;
                }else{
                    parent[rj] = ri;
                    rank[ri] += 1;
                }
                count--;
            }
        }
    }

在初始化Union时,将每个点的parent设为本身,且存在点满足条件(在本例中,grid[i][j]==1grid[i][j] == '1')时,应当递增Union对象的count属性。
在后续union的过程中,每当union一个点,执行count--操作。 经过这两步处理,count属性记录的就是图中的联通区域的个数,在本例中即是岛屿的个数。

通过Union对象来通过联通区域的个数

应用案例:leetcode-cn.com/problems/pa…

    public int minimumEffortPath(int[][] heights) {
        int m = heights.length;
        int n = heights[0].length;
        List<int[]> edges = new ArrayList<int[]>();
        // 对图进行遍历
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                int id = i * n + j;
                //  上方
                if (i > 0) {
                    edges.add(new int[]{id - n, id, Math.abs(heights[i][j] - heights[i - 1][j])});
                }
                //  左方
                if (j > 0) {
                    edges.add(new int[]{id - 1, id, Math.abs(heights[i][j] - heights[i][j - 1])});
                }
            }
        }
        //根据集合中的绝对值之差 排序
        Collections.sort(edges, new Comparator<int[]>() {
            public int compare(int[] edge1, int[] edge2) {
                return edge1[2] - edge2[2];
            }
        });

        UnionFind uf = new UnionFind(m * n);
        int ans = 0;
        for (int[] edge : edges) {
            int x = edge[0], y = edge[1], v = edge[2];
            uf.unite(x, y);
            if (uf.connected(0, m * n - 1)) {
                ans = v;
                break;
            }
        }
        return ans;
    }

在本例中,一条路径耗费的 体力值 是路径上相邻格子之间 高度差绝对值 的 最大值 决定的。求从左上角走到右下角的最小 体力消耗值 。
将两点的索引和体力值包装成数组,放入List中,根据体力值从小到大排序。从List中取出元素,联通数组中的两个点,然后判断此刻左上角和右下角是否联通,如果联通,则此时的体力值就是返回值。(从小到大排序,当某一刻联通时,该时刻的体力值就是该路径上的最大值)。