题目:给出一个树,求出所有作为根节点时树的高度最小的节点
思路:用剪枝的办法,每次剪掉叶子节点,最终剩下一个或者两个节点时结束。
原理:一个节点的树的高度为该节点到最远的节点的距离,且此最远节点必为叶子节点。
那么每一次剪枝后的图,剩余的节点对应的树的高度一定是未剪枝前的高度-1,即对于剪枝后的图,剩余节点之间树的高度的相互大小关系不变。
叶子节点的高度必定大于其父亲节点,所以剪枝相当于排除了叶子节点是高度最小的节点的情况。而剪枝后的图节点之间的高度关系不变,所以可以继续剪枝下去。直到剪枝不能再剪的时候,剩下的节点就是树的高度最小的节点。
若剩余三个节点以上,则必定有一节点不为叶子,必然可以继续剪枝。所以剪枝的结束状态为节点剩余2个以下。
此题难在原理证明上。想了好久才总结出来。其实算法什么的都是可以想到的,但是证明确实要花时间总结总结才行。
class Solution {
public:
vector<int> findMinHeightTrees(int n, vector<pair<int, int> >& edges) {
if (n == 1) return {0};
vector<unordered_set<int>> map(n);
for (auto edge : edges) {
map[edge.first].insert(edge.second);
map[edge.second].insert(edge.first);
}
queue<int> leaves;
int leaf;
for (int i = 0; i < n; ++i) {
if (map[i].size() == 1) leaves.push(i);
}
while (n > 2) {
int size = leaves.size();
n -= size;
for (int i = 0; i < size; ++i) {
leaf = leaves.front();
leaves.pop();
for (auto parent : map[leaf]) {
map[parent].erase(leaf);
if (map[parent].size() == 1) leaves.push(parent);
}
}
}
vector<int> result;
while (!leaves.empty()) {
result.push_back(leaves.front());
leaves.pop();
}
return result;
}
};