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]
Hint:
Show Hint- How many MHTs can a graph have at most?
Note:
(1) According to the definition of tree on Wikipedia: “a tree is an undirected graph in which any two vertices are connected by exactly one path. In other words, any connected graph without simple cycles is a tree.”
(2) The height of a rooted tree is the number of edges on the longest downward path between the root and a leaf.
一个图最多有两个MHT树,为距离最长的两个节点的中点。关键是怎么找出这两个相聚最远的节点。1)任选一个节点做遍历,找到距离最远的点;那么这个点是相聚最远的节点之一。2)从这个节点再做遍历,找到另外一个距离最远的节点。遍历过程中保存路径(前序),然后可以找到中点。
class Solution {
public:
vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) {
if (n <= 0) {
return vector<int>();
}
vector<set<int>> nodeEdges(n);
for (const auto& edge : edges) {
nodeEdges[edge.first].emplace(edge.second);
nodeEdges[edge.second].emplace(edge.first);
}
vector<int> distance(n);
vector<int> prevNodes(n);
bfs(nodeEdges, 0, distance, prevNodes);
int node1st = 0;
for (int i = 1; i < n; ++i) {
if (distance[i] > distance[node1st]) {
node1st = i;
}
}
bfs(nodeEdges, node1st, distance, prevNodes);
int node2nd = 0;
for (int i = 1; i < n; ++i) {
if (distance[i] > distance[node2nd]) {
node2nd = i;
}
}
vector<int> longestPath;
while (node2nd != -1) {
longestPath.push_back(node2nd);
node2nd = prevNodes[node2nd];
}
vector<int> result;
if ((longestPath.size() & 1) == 0) {
result.push_back(longestPath[longestPath.size() / 2 - 1]);
}
result.push_back(longestPath[longestPath.size() / 2]);
return result;
}
private:
void bfs(const vector<set<int>>& nodeEdges, int start, vector<int>& distance, vector<int>& prevNodes) {
vector<bool> visited(nodeEdges.size(), false);
queue<int> nodes;
nodes.push(start);
distance[start] = 0;
prevNodes[start] = -1;
while (!nodes.empty()) {
int curNode = nodes.front();
nodes.pop();
visited[curNode] = true;
for (const auto& neighbor : nodeEdges[curNode]) {
if (!visited[neighbor]) {
nodes.push(neighbor);
distance[neighbor] = distance[curNode] + 1;
prevNodes[neighbor] = curNode;
}
}
}
}
};
另外一种解法类似于拓扑排序,把度为1的节点一层层删除,相当于从边缘向核心推进,最后剩下的1个或者2个节点则为MHT树的根节点。
class Solution {
public:
vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) {
vector<set<int>> nodeEdges(n);
for (const auto& edge : edges) {
nodeEdges[edge.first].emplace(edge.second);
nodeEdges[edge.second].emplace(edge.first);
}
queue<int> curLeaves;
for (int i = 0; i < n; ++i) {
if (nodeEdges[i].size() <= 1) {
curLeaves.push(i);
}
}
if (n > 2) {
queue<int> nextLeaves;
while (!curLeaves.empty()) {
int leaf = curLeaves.front();
curLeaves.pop();
--n;
// Leaf node only has one neighbor node
int neighbor = *(nodeEdges[leaf].begin());
nodeEdges[neighbor].erase(leaf);
if (nodeEdges[neighbor].size() == 1) {
nextLeaves.push(neighbor);
}
if (curLeaves.empty() && n > 2) {
curLeaves.swap(nextLeaves);
}
}
curLeaves.swap(nextLeaves);
}
vector<int> result;
while (!curLeaves.empty()) {
result.push_back(curLeaves.front());
curLeaves.pop();
}
return result;
}
};