Leetcode 1584. 连接所有点的最小费用
并查集+最小生成树,不了解并查集和最小生成树的小伙伴建议可以先去了解这两种数据结构,然后再看答案就很容易看懂!本题题解参考leetcode的官方题解,但是去除了优化部分,更容易理解,另外加了详细的注释,方便日后复习,也希望能帮到其他小伙伴,如有错误,欢迎指正!
Java实现:
class Solution {
public int minCostConnectPoints(int[][] points) {
int n = points.length;
DisjointSetUnion dsu = new DisjointSetUnion(n); // 并查集
List<Edge> edges = new ArrayList<Edge>();
for (int i = 0; i < n; i++){
for (int j = 0; j < n; j++){
// 计算i和j两个点之间边的权重为两点的曼哈顿距离,全部存入edges中,形成一个完全图的边集
edges.add(new Edge(mDist(points,i,j),i,j));
}
}
// 比较所有边的大小,按照边的len从小到大将边重新排列
Collections.sort(edges,new Comparator<Edge>(){
public int compare(Edge edge1,Edge edge2){
return edge1.len - edge2.len;
}
});
int res = 0,num = 1;
// 从小到大遍历边集
for (Edge edge :edges){
int len = edge.len,x = edge.x,y = edge.y;
// 将一条边的两个节点进行并查集操作
// 1.如果两个节点的父节点相同,说明两个节点已经连通,无需加入这条边了,跳过
// 2.如果父节点不同,那么需要合并
if (dsu.unionSet(x,y)){
// 累加总费用
res += len;
num ++;
// 如果所有节点已经全部连通了,可以提前跳出循环
if (num == n){
break;
}
}
}
return res;
}
// 计算两点间的曼哈顿距离
public int mDist (int[][] points,int x,int y){
return Math.abs(points[x][0] - points[y][0]) + Math.abs(points[x][1] - points[y][1]);
}
}
class DisjointSetUnion{
int[] f;
int n;
// 构造函数,其实本题有两个数据结构,一个是边集edges,但是我们光有这个还不够,因为我们无法确认每条边的两个节点是否是连通的;
// 所以我们需要一个树的结构,方便快速通过递归的方式去确认两个节点是否是连通的,这就需要并查集DisjointSetUnion;
public DisjointSetUnion(int n){
this.n = n;
this.f = new int[n];
for (int i = 0; i < n; i++){
this.f[i] = i;
}
}
// 查,其实就是找根节点,f[x] == x代表x已经是根节点了,如果不满足说明还没找到根节点,一直递归
public int find(int x){
return f[x] == x ? x : (f[x] = find(f[x]));
}
// 并
public boolean unionSet(int x, int y){
int fx = find(x), fy = find(y);
// 是连通的
if (fx == fy){
return false;
}
f[fx] = fy; // 如果两个不连通,就必须要连通起来,连通的方式是fx认fy做父节点,并返回true
return true;
}
}
class Edge{
int len,x,y;
public Edge(int len,int x,int y){
this.len = len; // 边为曼哈顿距离
this.x = x;
this.y = y;
}
}
本博客参考题解:
链接:https://leetcode-cn.com/problems/min-cost-to-connect-all-points/solution/lian-jie-suo-you-dian-de-zui-xiao-fei-yo-kcx7/