最开始我是利用的暴力解法,对每个节点进行bfs,求得树的最大高度,然后取最大高度的最小值,然后果不其然超时了。后来看了别人的博客,发现有两种思路:
一、利用树的直径
这道题求解的实际上是树直径中间的那一个节点或两个结点,若直径为奇数个结点,则根节点为最中间的那个结点;若为偶数个结点,则为最中间的那两个结点
代码:
class Solution {
public:
int vis[10005];
int dis[10005];
int pre[10005];
vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
if(n==0)
return {};
if(n==1)
return {0};
vector<vector<int>>g(n);
for(auto e:edges){
g[e[0]].push_back(e[1]);
g[e[1]].push_back(e[0]);
}
queue<int>q;
q.push(0);
vis[0]=1;
int f;
while(!q.empty()){
f=q.front();
q.pop();
for (int i = 0; i < g[f].size(); i++) {
int v = g[f][i];
if(!vis[v]){
vis[v]=1;
q.push(v);
}
}
}
memset(vis,0,sizeof vis);
q.push(f);
vis[f]=1;
dis[f]=1;
pre[f]=-1;
while(!q.empty()){
f=q.front();
q.pop();
for (int i = 0; i < g[f].size(); i++) {
int v = g[f][i];
if(!vis[v]){
vis[v]=1;
dis[v] = dis[f] + 1;
pre[v]=f;
q.push(v);
}
}
}
vector<int>ans;
int maxl=dis[f];
int p=f;
for(int i=1;i<maxl/2;i++)
p=pre[p];
if(maxl%2==1){
p=pre[p];
ans.push_back(p);
}else{
ans.push_back(p);
p=pre[p];
ans.push_back(p);
}
return ans;
}
};
二、利用拓扑排序
思想就是通过不断消除叶子结点(即度为1的点),最后剩余的1个或者2个结点即是我们要得正确答案(画个示意图发现确实是这样,至于怎么证明我也不懂。。。)。方法基本跟求拓扑排序一样,分为三步:
①首先统计每个点的度,
②然后将度为1的点入栈或者入队列
③将栈中元素弹出,然后更新结点的度,然后回到第二步,直到结点数量小于等于2.
代码如下:
class Solution {
public:
int vis[10005];
vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
if(n==0)
return {};
if(n==1)
return {0};
vector<vector<int>>g(n);
vector<int> degree(n,0);
for(auto e:edges){
g[e[0]].push_back(e[1]);
g[e[1]].push_back(e[0]);
degree[e[0]]++;
degree[e[1]]++;
}
int num=n;
while(num>2){
stack<int> q;
for(int i=0;i<n;i++){
if(!vis[i]&°ree[i]==1){
q.push(i);
vis[i]=1;
num--;
}
}
while(!q.empty()){
int front = q.top();
q.pop();
for(int i=0;i<g[front].size();i++){
int u=g[front][i];
degree[u]--;
}
}
}
vector<int>ans;
for(int i=0;i<n;i++){
if(!vis[i])
ans.push_back(i);
}
return ans;
}
};
第一种方法会比第二种更快。