diff --git a/solutions/310. Minimum Height Trees.md b/solutions/310. Minimum Height Trees.md index 835dd80..2224c84 100644 --- a/solutions/310. Minimum Height Trees.md +++ b/solutions/310. Minimum Height Trees.md @@ -4,18 +4,78 @@ brute force思路就是从每个结点出发分别bfs把树高求出来, 然后返回树高最小的对应的根节点就行了. 但是这样要对每个结点进行bfs, 时间复杂度很高会超时. +## 思路一 + 题目给了一个提示: How many MHTs can a graph have at most? 稍加思考可以得出最多有两棵, 而且根节点就是直径(即距离最长的两个叶子间的距离)路径的中心结点, 如果直径为奇数那么只有一棵, 如果直径为偶数则有两棵. -所以我么可以先把这个直径求出来: 从任意点bfs到深度最大叶子,再从该叶子节点bfs到最远节点, -第二遍bfs的时候记录每个点的父节点, 最后就可以得到直径路径, 然后返回直径路径的中心结点就行了. +所以我么可以先把这个直径求出来: -上面的思路需要两次bfs, 时间复杂度为O(n). 其实此题还有个更加简便的方法求直径的中心结点: +从任意点bfs到深度最大叶子,再从该叶子节点bfs到最远节点,第二遍bfs的时候记录每个点的父节点, 最后就可以得到直径路径, 然后返回直径路径的中心结点就行了. + +时空复杂度为O(n) + +## 思路二 + +上面的思路需要两次bfs. 其实此题还有个更加简便的方法求直径的中心结点: * 去掉当前图的所有叶子节点,重复此操作直到只剩下一个或两个结点。 相当于是从最外面向内部进行dfs, 这个思路有点类似拓扑排序, 即题目[210. Course Schedule II](https://leetcode.com/problems/course-schedule-ii/), 可 参考[210题解](https://github.com/ShusenTang/LeetCode/blob/master/solutions/210.%20Course%20Schedule%20II.md)中的bfs思路. # C++ +## 思路一 +```C++ +class Solution { +private: + vectorfurthest_path_BFS(vector>&G, int start){ + /* + 从start开始bfs到深度最大叶子的一条路径 + */ + int n = G.size(), cur; + vectorvisited(n, false); + + vectorpath(n, -1); // path[i] = j 表示访问路径中节点j的父亲是i + queueq{{start}}; + + while(!q.empty()){ + cur = q.front(); q.pop(); + visited[cur] = true; + + for(int i: G[cur]){ + if(!visited[i]){ + q.push(i); + path[i] = cur; + } + } + } + // 此时cur就是bfs能到达的最远的节点之一 + vectorres; + while(cur != -1){ + res.push_back(cur); + cur = path[cur]; + } + + return res; + } +public: + vector findMinHeightTrees(int n, vector>& edges) { + vector>G(n); + + for(auto &e: edges){ + G[e[0]].push_back(e[1]); + G[e[1]].push_back(e[0]); + } + + vectortmp = furthest_path_BFS(G, 0); + vectordiameter = furthest_path_BFS(G, tmp[0]); // 最长直径 + + int d = diameter.size(); + if(d % 2) return {diameter[d/2]}; + return {diameter[d/2 - 1], diameter[d/2]}; + } +}; +``` +## 思路二 ``` C++ class Solution { public: