Skip to content

Commit fb1b153

Browse files
committed
feat: leetcode 310
1 parent 1042be2 commit fb1b153

File tree

7 files changed

+163
-0
lines changed

7 files changed

+163
-0
lines changed

assets/data/category.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1271,6 +1271,12 @@
12711271
"path": "../../problemset/range-sum-query-mutable/README.md",
12721272
"difficulty": "中等"
12731273
},
1274+
{
1275+
"id": 310,
1276+
"title": "最小高度树",
1277+
"path": "../../problemset/minimum-height-trees/README.md",
1278+
"difficulty": "中等"
1279+
},
12741280
{
12751281
"id": 393,
12761282
"title": "UTF-8 编码验证",

assets/data/problems.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2009,6 +2009,16 @@
20092009
"url": "https://leetcode-cn.com/problems/range-sum-query-mutable/",
20102010
"path": "../../problemset/range-sum-query-mutable/README.md"
20112011
},
2012+
{
2013+
"id": 310,
2014+
"title": {
2015+
"cn": "最小高度树",
2016+
"en": "minimum-height-trees"
2017+
},
2018+
"difficulty": "中等",
2019+
"url": "https://leetcode-cn.com/problems/minimum-height-trees/",
2020+
"path": "../../problemset/minimum-height-trees/README.md"
2021+
},
20122022
{
20132023
"id": 393,
20142024
"title": {

assets/docs/CATEGORY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@
253253
| 218. [天际线问题](../../problemset/the-skyline-problem/README.md) | 困难 |
254254
| 258. [各位相加](../../problemset/add-digits/README.md) | 简单 |
255255
| 307. [ 区域和检索 - 数组可修改](../../problemset/range-sum-query-mutable/README.md) | 中等 |
256+
| 310. [最小高度树](../../problemset/minimum-height-trees/README.md) | 中等 |
256257
| 393. [UTF-8 编码验证](../../problemset/utf-8-validation/README.md) | 中等 |
257258
| 420. [强密码检验器](../../problemset/strong-password-checker/README.md) | 困难 |
258259
| 521. [最长特殊序列](../../problemset/longest-uncommon-subsequence/README.md) | 简单 |

assets/docs/PROBLEMS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,8 @@
402402

403403
[307. 区域和检索 - 数组可修改](../../problemset/range-sum-query-mutable/README.md)
404404

405+
[310. 最小高度树](../../problemset/minimum-height-trees/README.md)
406+
405407
[393. UTF-8 编码验证](../../problemset/utf-8-validation/README.md)
406408

407409
[420. 强密码检验器](../../problemset/strong-password-checker/README.md)
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# 最小高度树
2+
3+
> 难度:中等
4+
>
5+
> https://leetcode-cn.com/problems/minimum-height-trees/
6+
7+
## 题目
8+
9+
树是一个无向图,其中任何两个顶点只通过一条路径连接。 换句话说,一个任何没有简单环路的连通图都是一棵树。
10+
11+
给你一棵包含 `n` 个节点的树,标记为 `0` 到 `n - 1` 。给定数字 n` 和一个有 `n - 1` 条无向边的 `edges` 列表(每一个边都是一对标签),其中 `edges[i] = [ai, bi]` 表示树中节点 `ai``bi` 之间存在一条无向边。
12+
13+
可选择树中任何一个节点作为根。当选择节点 `x` 作为根节点时,设结果树的高度为 `h` 。在所有可能的树中,具有最小高度的树(即,`min(h)`)被称为 **最小高度树**
14+
15+
请你找到所有的 **最小高度树** 并按 **任意顺序** 返回它们的根节点标签列表。
16+
17+
树的 **高度** 是指根节点和叶子节点之间最长向下路径上边的数量。
18+
19+
### 示例
20+
21+
#### 示例 1:
22+
23+
![minimum-height-trees-1](https://user-images.githubusercontent.com/54696834/161868696-47ec3e60-9a14-4f63-ad17-f8b9d79e97fa.jpg)
24+
25+
```
26+
输入:n = 4, edges = [[1,0],[1,2],[1,3]]
27+
输出:[1]
28+
解释:如图所示,当根是标签为 1 的节点时,树的高度是 1 ,这是唯一的最小高度树。
29+
```
30+
31+
#### 示例 2:
32+
33+
![minimum-height-trees-2](https://user-images.githubusercontent.com/54696834/161868698-43b003b1-58d5-4fcc-8170-27d77b9b189d.jpg)
34+
35+
```
36+
输入:n = 6, edges = [[3,0],[3,1],[3,2],[3,4],[5,4]]
37+
输出:[3,4]
38+
```
39+
40+
## 解题
41+
42+
```ts
43+
/**
44+
* 拓扑排序
45+
* @desc 时间复杂度 O(N) 空间复杂度 O(N)
46+
* @param n
47+
* @param edges
48+
* @returns
49+
*/
50+
export function findMinHeightTrees(n: number, edges: number[][]): number[] {
51+
if (n === 1) return [0]
52+
53+
const degree = new Array<number>(n).fill(0)
54+
const adj = new Array(n).fill([]).map(() => [] as number[])
55+
for (const edge of edges) {
56+
adj[edge[0]].push(edge[1])
57+
adj[edge[1]].push(edge[0])
58+
degree[edge[0]]++
59+
degree[edge[1]]++
60+
}
61+
62+
const queue: number[] = []
63+
// 将度为1的节点压入队列
64+
for (let i = 0; i < n; i++) {
65+
if (degree[i] === 1)
66+
queue.push(i)
67+
}
68+
69+
// 剩余节点
70+
let remainNodes = n
71+
while (remainNodes > 2) {
72+
const sz = queue.length
73+
remainNodes -= sz
74+
for (let i = 0; i < sz; i++) {
75+
const cur = queue.shift()!
76+
for (const v of adj[cur]) {
77+
degree[v]--
78+
if (degree[v] === 1)
79+
queue.push(v)
80+
}
81+
}
82+
}
83+
84+
return queue
85+
}
86+
```
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { describe, expect, it } from 'vitest'
2+
import { findMinHeightTrees } from '.'
3+
4+
describe('最小高度树', () => {
5+
testCase(findMinHeightTrees)
6+
})
7+
8+
function testCase(fn: (n: number, edges: number[][]) => number[]) {
9+
it.each([
10+
[4, [[1, 0], [1, 2], [1, 3]], [1]],
11+
[6, [[3, 0], [3, 1], [3, 2], [3, 4], [5, 4]], [3, 4]],
12+
])('示例%#', (n, edges, expected) => {
13+
expect(fn(n, edges)).toStrictEqual(expected)
14+
})
15+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/**
2+
* 拓扑排序
3+
* @desc 时间复杂度 O(N) 空间复杂度 O(N)
4+
* @param n
5+
* @param edges
6+
* @returns
7+
*/
8+
export function findMinHeightTrees(n: number, edges: number[][]): number[] {
9+
if (n === 1) return [0]
10+
11+
const degree = new Array<number>(n).fill(0)
12+
const adj = new Array(n).fill([]).map(() => [] as number[])
13+
for (const edge of edges) {
14+
adj[edge[0]].push(edge[1])
15+
adj[edge[1]].push(edge[0])
16+
degree[edge[0]]++
17+
degree[edge[1]]++
18+
}
19+
20+
const queue: number[] = []
21+
// 将度为1的节点压入队列
22+
for (let i = 0; i < n; i++) {
23+
if (degree[i] === 1)
24+
queue.push(i)
25+
}
26+
27+
// 剩余节点
28+
let remainNodes = n
29+
while (remainNodes > 2) {
30+
const sz = queue.length
31+
remainNodes -= sz
32+
for (let i = 0; i < sz; i++) {
33+
const cur = queue.shift()!
34+
for (const v of adj[cur]) {
35+
degree[v]--
36+
if (degree[v] === 1)
37+
queue.push(v)
38+
}
39+
}
40+
}
41+
42+
return queue
43+
}

0 commit comments

Comments
 (0)