返回
敏捷探索最小高度树:LeetCode 310 解题指南
前端
2024-02-16 14:44:39
前言
在计算机科学的世界中,树形结构无处不在,从文件系统到网络拓扑,它们都扮演着至关重要的角色。本文将深入探讨 LeetCode 上的 310. 最小高度树,探索如何找出给定加权无向图中高度最小的树。
问题陈述
给定一个加权无向图,其中顶点由数字标识,并且每个边都有一个权重。目标是找到一棵高度最小的树,其中树的高度定义为根节点到最远叶子节点的最长路径长度。
解题方法
克鲁斯卡尔算法
克鲁斯卡尔算法是一种贪心算法,用于求解加权无向图中的最小生成树。我们可以使用它来解决 310. 最小高度树,因为最小高度树实际上就是加权无向图中的最小生成树。
算法的步骤如下:
- 将图中的所有顶点初始化为单独的连通分量。
- 从所有边中选择一条权重最小的边。
- 如果选择的边连接了两个不同的连通分量,则将这两个连通分量合并为一个连通分量,并将该边添加到最小生成树中。
- 重复步骤 2 和 3,直到所有的顶点都连接在一个连通分量中。
Prim 算法
Prim 算法也是一种贪心算法,用于求解加权无向图中的最小生成树。与克鲁斯卡尔算法不同,Prim 算法从一个顶点开始,逐步扩展最小生成树,直到所有的顶点都包括在内。
算法的步骤如下:
- 从图中任意选择一个顶点作为根节点。
- 将根节点添加到最小生成树中。
- 从根节点开始,为每个尚未添加到最小生成树中的顶点找到权重最小的边。
- 如果边连接了未添加到最小生成树中的顶点,则将该边和顶点添加到最小生成树中。
- 重复步骤 3 和 4,直到所有的顶点都添加到最小生成树中。
代码示例
以下是使用克鲁斯卡尔算法解决 LeetCode 310. 最小高度树的 C++ 代码示例:
#include <vector>
#include <algorithm>
using namespace std;
struct Edge {
int from, to, weight;
};
bool compareEdges(const Edge& a, const Edge& b) {
return a.weight < b.weight;
}
class DSU {
public:
vector<int> parent, rank;
DSU(int n) {
parent.resize(n);
rank.resize(n, 0);
for (int i = 0; i < n; i++) {
parent[i] = i;
}
}
int find(int x) {
if (parent[x] != x) {
parent[x] = find(parent[x]);
}
return parent[x];
}
void union(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY) {
if (rank[rootX] > rank[rootY]) {
parent[rootY] = rootX;
} else if (rank[rootX] < rank[rootY]) {
parent[rootX] = rootY;
} else {
parent[rootY] = rootX;
rank[rootX]++;
}
}
}
};
vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
// 1. Sort edges by weight
vector<Edge> edges_sorted;
for (auto& edge : edges) {
edges_sorted.push_back({edge[0], edge[1], edge[2]});
}
sort(edges_sorted.begin(), edges_sorted.end(), compareEdges);
// 2. Create DSU
DSU dsu(n);
// 3. Process edges
vector<int> minHeightTrees;
for (auto& edge : edges_sorted) {
int rootX = dsu.find(edge.from);
int rootY = dsu.find(edge.to);
if (rootX != rootY) {
dsu.union(rootX, rootY);
if (minHeightTrees.empty()) {
minHeightTrees.push_back(edge.from);
minHeightTrees.push_back(edge.to);
} else {
minHeightTrees.clear();
minHeightTrees.push_back(edge.from);
minHeightTrees.push_back(edge.to);
}
}
}
return minHeightTrees;
}
复杂度分析
克鲁斯卡尔算法和 Prim 算法的时间复杂度都是 O(E log V),其中 E 是图中的边数,V 是顶点数。在 310. 最小高度树中,图是一棵树,所以 E = V - 1,因此算法的时间复杂度为 O(V log V)。
结论
本文详细介绍了如何使用克鲁斯卡尔算法和 Prim 算法解决 LeetCode 310. 最小高度树。这些算法提供了高效的方法来求解加权无向图中的最小生成树,从而找出最小高度树。理解这些算法对于解决图论问题至关重要,并且它们在计算机科学的各个领域都有广泛的应用。