For a undirected graph with tree characteristics, we can choose any node as the root. The result graph is then a rooted tree. Among all possible rooted trees, those with minimum height are called minimum height trees (MHTs). Given such a graph, write a function to find all the MHTs and return a list of their root labels.
Format
The graph contains n
nodes which are labeled from 0
to n - 1
. You will be given the number n
and a list of undirected edges
(each edge is a pair of labels).
You can assume that no duplicate edges will appear in edges
. Since all edges are undirected, [0, 1]
is the same as [1, 0]
and thus will not appear together in edges
.
Example 1:
Given n = 4
, edges = [[1, 0], [1, 2], [1, 3]]
0 | 1 / \ 2 3
return [1]
Example 2:
Given n = 6
, edges = [[0, 3], [1, 3], [2, 3], [4, 3], [5, 4]]
0 1 2 \ | / 3 | 4 | 5
return [3, 4]
思路是找到最长路径,然后找中间点,暴力bfs搜索(超时了):
class Solution {
public:
vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) {
vector< vector<pair<int,int>>> graph;
vector<pair<int,int>>temp;
for (int i=0;i<n;i++)
graph.push_back(temp);
for (int i=0;i<edges.size();i++){
graph[edges[i].first].push_back(edges[i]);
graph[edges[i].second].push_back(edges[i]);
}
int max_len=0;
vector< vector<int> > max_list;
queue<vector<int>> que;
for (int i=0;i<n;i++){
if (graph[i].size()==1){
vector<int> temp;
temp.push_back(i);
que.push(temp);
}
}
while (!que.empty()){
vector<int> vec=que.front();
// for (int i=0;i<vec.size();i++)
// cout<<vec[i]<<" ";
// cout<<endl;
//que.pop();
if (vec.size()>max_len){
max_list.clear();
max_list.push_back(vec);
max_len=vec.size();
}
else{
if (vec.size()==max_len)
max_list.push_back(vec);
}
int end_num=vec[vec.size()-1];
for (int i=0;i<graph[ end_num ].size();i++){
int next_num;
if (graph[end_num][i].first!=end_num)
next_num=graph[end_num][i].first;
else
next_num=graph[end_num][i].second;
if (vec.size()==1){
vec.push_back(next_num);
que.push(vec);
}
else
if (next_num!=vec[vec.size()-2]){
vec.push_back(next_num);
que.push(vec);
}
vec=que.front();
}
que.pop();
}
//cout<<max_len<<endl;
vector<int> res;
for (int i=0;i<max_list.size();i++){
if (max_list[i].size()%2==1){
if (!contain(res,max_list[i][ max_list[i].size()/2 ]))
res.push_back(max_list[i][ max_list[i].size()/2 ]);
}
else{
if (!contain(res,max_list[i][ max_list[i].size()/2 ]))
res.push_back(max_list[i][ max_list[i].size()/2 ]);
if (!contain(res,max_list[i][ max_list[i].size()/2-1 ]))
res.push_back(max_list[i][ max_list[i].size()/2-1 ]);
}
}
return res;
}
bool contain(vector<int>& vec, int n){
for (int i=0;i<vec.size();i++)
if (vec[i]==n)
return true;
return false;
}
};
换一种思路, 受到网上解答的启发:
还是找最长的一条路径,但是从两边同时开始删除节点,最后剩下的肯定是所求的点。
如果从树的角度来看的话,不停地删除外围节点(高度为1的点),最后剩下来的一个node或者两个node,肯定是所需要的。
表用unordered_set 来实现:
class Solution {
public:
vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) {
vector<unordered_set<int>> vec;
vector<int>res;
if (edges.empty()){
res.push_back(0);
return res;
}
int num_nodes=n;
for (int i=0;i<n;i++){
unordered_set<int> set;
vec.push_back(set);
}
for (int i=0;i<edges.size();i++){
int n1=edges[i].first;
int n2=edges[i].second;
vec[n1].insert(n2);
vec[n2].insert(n1);
}
queue<int> que;
for (int i=0;i<n;i++){
if (vec[i].size()==1){
que.push(i);
}
}
while (num_nodes>2){
int len=que.size();
for (int i=0;i<len;i++){
int son=que.front();
que.pop();
num_nodes--;
int par=*vec[son].begin();
vec[par].erase(son);
if(vec[par].size()==1)
que.push(par);
}
}
while(!que.empty()){
res.push_back(que.front());
que.pop();
}
return res;
}
};