这里只是给出BFS的算法,还有官方题解中未解释的部分(为什么某一个节点的最远节点x,x的最远节点y,(x,y)的路径为什么是最长路径?)
树是一个无向图,其中任何两个顶点只通过一条路径连接。 换句话说,一个任何没有简单环路的连通图都是一棵树。
给你一棵包含 n
个节点的树,标记为 0
到 n - 1
。给定数字 n
和一个有 n - 1
条无向边的 edges
列表(每一个边都是一对标签),其中 edges[i] = [ai, bi]
表示树中节点 ai
和 bi
之间存在一条无向边。
可选择树中任何一个节点作为根。当选择节点 x
作为根节点时,设结果树的高度为 h
。在所有可能的树中,具有最小高度的树(即,min(h)
)被称为 最小高度树 。
请你找到所有的 最小高度树 并按 任意顺序 返回它们的根节点标签列表。
树的 高度 是指根节点和叶子节点之间最长向下路径上边的数量。
示例 1:
输入:n = 4, edges = [[1,0],[1,2],[1,3]] 输出:[1] 解释:如图所示,当根是标签为 1 的节点时,树的高度是 1 ,这是唯一的最小高度树。
示例 2:
输入:n = 6, edges = [[3,0],[3,1],[3,2],[3,4],[5,4]] 输出:[3,4]
提示:
1 <= n <= 2 * 104
edges.length == n - 1
0 <= ai, bi < n
ai != bi
- 所有
(ai, bi)
互不相同 - 给定的输入 保证 是一棵树,并且 不会有重复的边
//
// Created by py on 24-3-17.
//
#include <iostream>
#include <vector>
#include <queue>
#include <unordered_map>
#include <deque>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <map>
using namespace std;
class Solution {
public:
int findLongestNode(int u, vector<int> &parent, vector<vector<int>> &adj) {
int n = adj.size();
queue<int> qu;
vector<bool> visit(n);
qu.emplace(u);
visit[u] = true;
int node = -1;
while (!qu.empty()) {
int curr = qu.front();
qu.pop();
node = curr;
for (auto &v: adj[curr]) {
if (!visit[v]) {
visit[v] = true;
parent[v] = curr;
qu.emplace(v);
}
}
}
return node;
}
vector<int> findMinHeightTrees(int n, vector<vector<int>> edges) {
//特殊情况
if (n == 1) {
return {0};
}
//构建邻接表
vector<vector<int>> adj(n);
for (auto &edge: edges) {
adj[edge[0]].emplace_back(edge[1]);
adj[edge[1]].emplace_back(edge[0]);
}
vector<int> parent(n, -1);
/* 本处有一个疑问:为什么要求最长路径 ?请看
* https://leetcode.cn/problems/minimum-height-trees/solutions/1395249/zui-xiao-gao-du-shu-by-leetcode-solution-6v6f/
* 在某一条无向无环路中,任意一个节点的最远节点为x,x的最远节点为y,这条路的最长的路即为:x,y
* 可证明:设有一无向无环图(有向的话清参考拓扑排序算法),取任意节点 x
* 利用贪心思想 , 寻找节点 x 最长的路,该路必为叶子节点 y,无子节点。
* 反证法证明上述:假如不为叶子节点,最远距离 dis[x][y]
* 又因 y 存在叶子节点 z ,存在 dis[x][z] > dis[x][y]与最长矛盾
* 又因为是叶子节点 y ,寻找其最远的节点 z ,z也比为某一个叶子节点(上述已然证明)
* 证明: dis[y][z] = maxNode
* dis[x][y] 为 x 的最长路径
* dis[y][z] 为 z 的最长路径
* 本处又利用反证法:假设存在 两个节点 node1,node2 dis[node1][node2] > dis[y][z]
* 设任意节点 a , 都存在:由上式 (dis[node1][node2] > dis[y][z])
* 有dis[node1][a] + dis[a][node2] > dis[y][a] + dis[a][z]
* 但又与前边的 假设 x 节点违背,故矛盾
* 最后得出:dis[y][z] = maxNode
* */
/* 找到与节点 0 最远的节点 x */
int x = findLongestNode(0, parent, adj);
/* 找到与节点 x 最远的节点 y */
int y = findLongestNode(x, parent, adj);
/* 求出节点 x 到节点 y 的路径 */
vector<int> path;
parent[x] = -1;
while (y != -1) {
path.emplace_back(y);
y = parent[y];
}
int m = path.size();
if (m % 2 == 0) {
return {path[m / 2 - 1], path[m / 2]};
} else {
return {path[m / 2]};
}
}
};
int main() {
Solution solution;
vector<int> trees = solution.findMinHeightTrees(6, {{0, 1},
{0, 2},
{0, 3},
{3, 4},
{5, 4}});
for (const auto &item: trees) {
cout << item << " ";
}
return 0;
}