对于一个具有树特征的无向图,我们可选择任何一个节点作为根。图因此可以成为树,在所有可能的树中,具有最小高度的树被称为最小高度树。给出这样的一个图,写出一个函数找到所有的最小高度树并返回他们的根节点。
格式
该图包含 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]
说明:
- 根据树的定义,树是一个无向图,其中任何两个顶点只通过一条路径连接。 换句话说,一个任何没有简单环路的连通图都是一棵树。
- 树的高度是指根节点和叶子节点之间最长向下路径上边的数量。
解题思路:
最开始我是把每一个点的最大深度求出来,然后将最小长度的点存进一个容器中返回结果,但是超时了.
因为在这个过程中没有发现其实最小高度树的特点是根位于某条最长路径的中点,所以其余的点的长度计算都是多余的。
那么怎么得到中间的那一个或者两个点呢?
通过一层一层地将边缘的叶子节点去掉之后,最后保存下来的一个或者两个点就是结果。这里用一个结构体,其中set用来保存一个节点的邻居.当去除叶子节点时,将叶子节点从邻居节点中删除。
code:
class Solution {
public:
struct node{
set<int>neibor;
bool isleaf(){return neibor.size()==1;}
};
vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges)
{
if(n==0)return {};
if(n==1)return {0};
vector<node>tree(n);
for(auto p:edges)
{
tree[p.first].neibor.insert(p.second);
tree[p.second].neibor.insert(p.first);
}
vector<int>cur_leafs;
vector<int>next_leafs;
for(int i=0;i<n;i++)
if(tree[i].isleaf())cur_leafs.push_back(i);
while(1)
{
for(auto leaf:cur_leafs)
{
set<int>neibors=tree[leaf].neibor;
for(auto neibor:neibors)
{
tree[neibor].neibor.erase(leaf);
if(tree[neibor].isleaf())next_leafs.push_back(neibor);
}
}
if(next_leafs.empty())
{
break;
}
cur_leafs.clear();
swap(cur_leafs,next_leafs);
}
return cur_leafs;
}
};