拓扑排序法
步骤:每次·删除所有当前入度为1的结点,直到最后剩下的节点数<=2
原理:
1.删除度为1的结点:相当于剪去所有当前的叶节点,最小高度树的层数必然下降一层
(1)所以最小高度树的高度等于(删除次数+剩下结点数)(假设只有一个结点时高度为1)
2.最后结点数 <= 2
(1)最后剩下一个结点,则该节点为唯一解
(2)最后剩下两个结点:以这两个结点为根的树都是最小高度树
(3)最后剩下三个结点:那么必然有两个度为1的结点和一个度大于1的结点,可再次通过删除所有度为1的结点进而使得树的高度下降1
(4)最后剩下结点 > 3:与(3)同理,可以通过剪枝使得树高度下降
vector<int> findMinHeightTrees(int n,vector<vector<int>>& edges){
if(n == 1)
return {0};
else if(n == 2)
return {0, 1};
int indegree[n];
memset(indegree, 0, sizeof(int) * n);
vector<vector<int>> graph(n, vector<int>());
//构建入度和图
for(vector<int> &edge : edges){
++indegree[edge[0]];
++indegree[edge[1]];
graph[edge[0]].push_back(edge[1]);
graph[edge[1]].push_back(edge[0]);
}
//初始化插入入度为1的结点
queue<int> 1;
for(int i = 0; i < n; i++){
if(indegree[i] == 1)
q.push(i);
}
//拓扑排序
while(n > 2){
n -= q.size();
for(int i = q.size(); i > 0; i--){
int curr = q.front();
q.pop();
indegree[curr] = 0; //度设为0
for(int next : graph[curr]){
//只考虑入度不为0的情况,即没有被遍历过
if(indegree[next] != 0){
--indegree[next];
if(indegree[next] == 1)
q.push(next);
}
}
}
}
//队列里剩下的就是根节点
vector<int> res;
while(!q.empty()){
res.push_back(q.front());
q.pop();
}
return res;
}