1584. 连接所有点的最小费用(并查集)

package com.heu.wsq.leetcode.bingchaji;

import java.util.*;

/**
 * 1584. 连接所有点的最小费用
 * @author wsq
 * @date 2021/1/19
 * 给你一个points 数组,表示 2D 平面上的一些点,其中 points[i] = [xi, yi] 。
 * 连接点 [xi, yi] 和点 [xj, yj] 的费用为它们之间的 曼哈顿距离 :|xi - xj| + |yi - yj| ,其中 |val| 表示 val 的绝对值。
 * 请你返回将所有点连接的最小总费用。只有任意两点之间 有且仅有 一条简单路径时,才认为所有点都已连接。
 *  示例 1:
 *
 * 输入:points = [[3,12],[-2,5],[-4,1]]
 * 输出:18
 *
 * 链接:https://leetcode-cn.com/problems/min-cost-to-connect-all-points
 */
public class MinCostConnectPoints {
    /**
     * 1.计算各个点之间的边长
     * 2.排序边长集合,从小到大遍历边长
     * 3.利用并查集判断两点是否连通,若已经连通,则忽略当前边
     * @param points
     * @return
     */
    public int minCostConnectPoints(int[][] points){
        int n = points.length;
        UnionFind unionFind = new UnionFind(n);
        // 计算两点之间的边的距离
        List<Edge> list = new ArrayList<>();
        for (int i = 0; i < n; i++){
            for (int j = i + 1; j < n; j++){
                list.add(new Edge(dist(points, i, j), i, j));
            }
        }
        // 按照边长从小到大排序边
        Collections.sort(list, new Comparator<Edge>() {
            @Override
            public int compare(Edge o1, Edge o2) {
                return o1.len - o2.len;
            }
        });

        // 统计总长度
        int ret = 0, num = 1;
        for (Edge edge : list) {
            int len = edge.len, x = edge.x, y = edge.y;
            if (!unionFind.isConnected(x, y)){
                unionFind.union(x, y);
                ret += len;
                num++;
                if (num == n){
                    break;
                }
            }
        }
        return ret;
    }

    private int dist(int[][] points, int i, int j) {
        return Math.abs(points[i][0] - points[j][0]) + Math.abs(points[i][1] - points[j][1]);
    }

    private class UnionFind{
        private int[] parent;
        private int[] rank;
        private int n;

        public UnionFind(int n){
            this.n = n;
            this.rank = new int[n];
            this.parent = new int[n];
            Arrays.fill(rank, 1);
            for (int i = 0; i < n; i++) {
                this.parent[i] = i;
            }
        }

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

        public void union(int x, int y){
            int rootX = find(x);
            int rootY = find(y);
            if (rootX == rootY){
                return;
            }
            if (rank[rootX] < rank[rootY]){
                int tmp = rootX;
                rootX = rootY;
                rootY = tmp;
            }
            rank[rootX] += rank[rootY];
            parent[rootY] = parent[rootX];
        }

        public boolean isConnected(int x, int y){
            return find(x) == find(y);
        }
    }
}

class Edge{
    int x;
    int y;
    int len;
    public Edge(int len, int x, int y){
        this.x = x;
        this.y = y;
        this.len = len;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值