QUESTION
medium
题目描述
对于一个具有树特征的无向图,我们可选择任何一个节点作为根。图因此可以成为树,在所有可能的树中,具有最小高度的树被称为最小高度树。给出这样的一个图,写出一个函数找到所有的最小高度树并返回他们的根节点。
格式:
- 该图包含
n
个节点,标记为0
到n - 1
。给定数字 n 和一个无向边edges
列表(每一个边都是一对标签)。 - 你可以假设没有重复的边会出现在 edges 中。由于所有的边都是无向边,[0, 1] 和 [1, 0] 是相同的,因此不会同时出现在 edges 里。
示例 1:
输入: n = 4, edges = [[1, 0], [1, 2], [1, 3]]
0
|
1
/ \
2 3
输出: [1]
示例 2:
输入: n = 6, edges = [[0, 3], [1, 3], [2, 3], [4, 3], [5, 4]]
0 1 2
\ | /
3
|
4
|
5
输出: [3, 4]
说明
- 根据树的定义,树是一个无向图,其中任何两个顶点只通过一条路径连接。 换句话说,一个任何没有简单环路的连通图都是一棵树。
- 树的高度是指根节点和叶子节点之间最长向下路径上边的数量。
SOLUTION
一开始我写了一个很低效的方法(不能 AC,如下),这个方法计算每个节点作为根时其树的高度。通过计算出所有节点的高度,输出最小高度的情况的答案。但是超出时限(几百个点的图,算爆了)。
class Solution {
public:
vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) {
unordered_map<int, vector<int>> m;
vector<int> res;
int min = INT_MAX;
for(auto e : edges){
m[e.first].push_back(e.second);
m[e.second].push_back(e.first);
}
for(int i = 0; i < n; i++){
int currH = getHeight(i, m);
if(currH < min){
res.clear();
res.push_back(i);
min = currH;
}
else if(currH == min){
res.push_back(i);
}
}
return res;
}
int getHeight(int node, unordered_map<int, vector<int>>& m) {
set<int> checked;
queue<int> q;
int h = -1;
q.push(node);
checked.insert(node);
while(!q.empty()){
h++;
int qsize = q.size();
while(qsize){
qsize--;
int curr = q.front(); q.pop();
for(auto e : m[curr]) if(checked.insert(e).second) q.push(e);
}
}
return h;
}
};
经过对以上代码一系列的优化,仍然超出时限,看来这样的方法并不可取。(有 DFS 通过的,没有尝试)
方法一
实则无奈,看了 Leetcode 的评论,得到了一种巧妙的方法:
- 首先构建一个图
- 然后剥掉最外面的一层(删除当前图所有的叶子节点,叶子节点即只有一条连边的节点)
- 重复步骤 2,直至只剩下 1 个或 2 个节点
class Solution {
public:
vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) {
if(n == 1) return {0};
vector<unordered_set<int>> g(n); //这是一个图,保存了 g[i] 可到的下一个点的集合
vector<int> res;
queue<int> q; //用于保存叶节点的队列
for(auto e : edges){ //构造图
g[e.first].insert(e.second);
g[e.second].insert(e.first);
}
for(int i = 0; i < n; i++){ //找叶节点
if(g[i].size() == 1) q.push(i);
}
while(n > 2) {
int size = q.size();
n -= size;
for(int i = 0; i < size; ++i) {
int t = q.front(); q.pop();
for(auto e : g[t]) {
g[e].erase(t);
if(g[e].size() == 1) q.push(e);
}
}
}
while(!q.empty()) {
res.push_back(q.front()); q.pop();
}
return res;
}
};