一道需要我们事先做一些分析的题目,一个图中可能有多少这样的节点,可以使以其为根节点的时候深度最小。事实上,这样的节点只可能在最长的路径上,并且一定是最中间的一个或者两个节点。假设tree中最长的路径p长度为d,那么我们取中点为root的时候整个tree的最大的深度就是d/2, 因为假设有其他的点c深度超过d/2,那么把p的一半和root再与c相连,整个长度肯定是大于d的,这和我们的假设矛盾。假设有其他不在p上的点n可以在其当root的时候使整个tree的深度小于d/2,那么既然n不在p上,那么因为从p的两头到点n肯定分别只有一条路径(否则会有环),并且共同经过p上的某个节点,那么p的两个端节点,深度是不可能小于d/2的,我们得到了矛盾的结论。所以假设成立,那么找tree中最长的路径,我们可以用DFS或者BFS,DFS的话,我们从任意节点开始,找到某个叶节点,然后从叶节点DFS找到最长路径,然后去其中点即可,假设我们总共有N个节点,那么有N-1条边(N个节点connected至少需要N-1条边,大于N-1条边会产生环),建图和DFS都是O(N),所以总的时间复杂度就是O(N),代码如下:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Solution { | |
public: | |
vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) { | |
if(n <= 0)return {}; | |
vector<vector<int>> g(n, vector<int>()); | |
for(auto e : edges) | |
{ | |
g[e.first].push_back(e.second); | |
g[e.second].push_back(e.first); | |
} | |
vector<int> longest, curr; | |
longestPath(g, -1, 0, curr, longest); | |
int end = longest[longest.size() - 1]; | |
longest = vector<int>(); | |
longestPath(g, -1, end, curr, longest); | |
vector<int> res; | |
res.push_back(longest[(longest.size() - 1) / 2]); | |
if (!(longest.size() % 2))res.push_back(longest[(longest.size() - 1) / 2 + 1]); | |
return res; | |
} | |
private: | |
void longestPath(vector<vector<int>>& g, int from, int to, vector<int>& curr, vector<int>& longest) | |
{ | |
curr.push_back(to); | |
for(auto v : g[to]) | |
{ | |
if(v != from)longestPath(g, to, v, curr, longest); | |
} | |
if(curr.size() > longest.size())longest = curr; | |
curr.pop_back(); | |
} | |
}; |
BFS的话,我们就类似剥洋葱,从外部的叶节点开始向里面一层一层的删除,知道最后剩下的一个或者两个节点,就是最长路径上的中点,时间复杂度O(N), 代码如下:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Solution { | |
public: | |
vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) { | |
unordered_map<int, vector<int>> g; | |
unordered_map<int, int> degrees; | |
for(auto& e : edges) | |
{ | |
g[e.first].emplace_back(e.second); | |
g[e.second].emplace_back(e.first); | |
++degrees[e.first]; | |
++degrees[e.second]; | |
} | |
//collect leaves | |
queue<int> leaves; | |
for(int i = 0; i < n; ++i) | |
if(degrees[i] <= 1)//single node has 0 degree | |
leaves.push(i); | |
//peel onion | |
while(n > 2) | |
{ | |
int len = leaves.size(); | |
for(int i = 0; i < len; ++i) | |
{ | |
int leave = leaves.front(); | |
leaves.pop(); | |
for(auto adj : g[leave]) | |
if(--degrees[adj] == 1) | |
leaves.push(adj); | |
} | |
n -= len; | |
} | |
vector<int> res; | |
while(leaves.size()) | |
{ | |
res.emplace_back(leaves.front()); | |
leaves.pop(); | |
} | |
return res; | |
} | |
}; |
No comments:
Post a Comment