0310. 最小高度树【中等】
1. 📝 题目描述
树是一个无向图,其中任何两个顶点只通过一条路径连接。 换句话说,任何一个没有简单环路的连通图都是一棵树。
给你一棵包含 n 个节点的树,标记为 0 到 n - 1。给定数字 n 和一个有 n - 1 条无向边的 edges 列表(每一个边都是一对标签),其中 edges[i] = [ai, bi] 表示树中节点 ai 和 bi 之间存在一条无向边。
可选择树中任何一个节点作为根。当选择节点 x 作为根节点时,设结果树的高度为 h。在所有可能的树中,具有最小高度的树(即,min(h))被称为 最小高度树。
请你找到所有的 最小高度树 并按 任意顺序 返回它们的根节点标签列表。
树的 高度 是指根节点和叶子节点之间最长向下路径上边的数量。
示例 1:

txt
输入:n = 4, edges = [[1,0],[1,2],[1,3]]
输出:[1]
解释:如图所示,当根是标签为 1 的节点时,树的高度是 1,这是唯一的最小高度树。1
2
3
2
3
示例 2:

txt
输入:n = 6, edges = [[3,0],[3,1],[3,2],[3,4],[5,4]]
输出:[3,4]1
2
2
提示:
1 <= n <= 2 * 10^4edges.length == n - 10 <= ai, bi < nai != bi- 所有
(ai, bi)互不相同 - 给定的输入 保证 是一棵树,并且 不会有重复的边
2. 🎯 s.1 - 拓扑排序剥叶
c
int* findMinHeightTrees(int n, int** edges, int edgesSize, int* edgesColSize, int* returnSize) {
if (n == 1) {
int* res = (int*)malloc(sizeof(int));
res[0] = 0; *returnSize = 1;
return res;
}
int* degree = (int*)calloc(n, sizeof(int));
int** graph = (int**)malloc(sizeof(int*) * n);
int* gSize = (int*)calloc(n, sizeof(int));
int* gCap = (int*)malloc(sizeof(int) * n);
for (int i = 0; i < n; i++) { gCap[i] = 4; graph[i] = (int*)malloc(sizeof(int) * 4); }
for (int i = 0; i < edgesSize; i++) {
int a = edges[i][0], b = edges[i][1];
if (gSize[a] == gCap[a]) { gCap[a] *= 2; graph[a] = realloc(graph[a], sizeof(int) * gCap[a]); }
if (gSize[b] == gCap[b]) { gCap[b] *= 2; graph[b] = realloc(graph[b], sizeof(int) * gCap[b]); }
graph[a][gSize[a]++] = b;
graph[b][gSize[b]++] = a;
degree[a]++; degree[b]++;
}
int* leaves = (int*)malloc(sizeof(int) * n);
int lSize = 0;
for (int i = 0; i < n; i++) if (degree[i] == 1) leaves[lSize++] = i;
int remaining = n;
while (remaining > 2) {
remaining -= lSize;
int* newLeaves = (int*)malloc(sizeof(int) * n);
int nlSize = 0;
for (int i = 0; i < lSize; i++) {
int leaf = leaves[i];
for (int j = 0; j < gSize[leaf]; j++) {
int nb = graph[leaf][j];
if (--degree[nb] == 1) newLeaves[nlSize++] = nb;
}
}
free(leaves);
leaves = newLeaves;
lSize = nlSize;
}
*returnSize = lSize;
for (int i = 0; i < n; i++) free(graph[i]);
free(graph); free(gSize); free(gCap); free(degree);
return leaves;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
js
/**
* @param {number} n
* @param {number[][]} edges
* @return {number[]}
*/
var findMinHeightTrees = function (n, edges) {
if (n === 1) return [0]
const degree = new Array(n).fill(0)
const graph = Array.from({ length: n }, () => [])
for (const [a, b] of edges) {
graph[a].push(b)
graph[b].push(a)
degree[a]++
degree[b]++
}
let leaves = []
for (let i = 0; i < n; i++) {
if (degree[i] === 1) leaves.push(i)
}
let remaining = n
while (remaining > 2) {
remaining -= leaves.length
const newLeaves = []
for (const leaf of leaves) {
for (const neighbor of graph[leaf]) {
if (--degree[neighbor] === 1) newLeaves.push(neighbor)
}
}
leaves = newLeaves
}
return leaves
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
py
class Solution:
def findMinHeightTrees(self, n: int, edges: List[List[int]]) -> List[int]:
if n == 1:
return [0]
degree = [0] * n
graph = [[] for _ in range(n)]
for a, b in edges:
graph[a].append(b)
graph[b].append(a)
degree[a] += 1
degree[b] += 1
leaves = [i for i in range(n) if degree[i] == 1]
remaining = n
while remaining > 2:
remaining -= len(leaves)
new_leaves = []
for leaf in leaves:
for nb in graph[leaf]:
degree[nb] -= 1
if degree[nb] == 1:
new_leaves.append(nb)
leaves = new_leaves
return leaves1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- 时间复杂度:
,其中 是节点数 - 空间复杂度:
,邻接表和度数组
算法思路:
- 不断移除度为 1 的叶子节点,直到剩余节点不超过 2 个
- 最后剩下的 1 或 2 个节点即为最小高度树的根