🔗 https://leetcode.com/problems/find-minimum-diameter-after-merging-two-trees
题目
- 合并两个 tree,使得 tree 的直径最小,返回最小值
- tree 的直径,是任意两个 node 之间 edge 条数的最大值
思路
- 合并后的 tree 的直径的最小值,是以下情况的最大值
- tree 1 的直径
- tree 2 的直径
- tree 1 最低高度 + tree 2 最低高度 + 1
- 算 tree 的最低高度的朴素算法是,枚举起始点,dfs 或者 bfs 计算其其高度。tree 的直径是,上述高度的最大值。这样的算法时间复杂度高,会 TLE
- tree 的最低高度为 tree 的直径/2 的 ceil,tree 的直径可以通过两遍 bfs 计算得出
- 假设 tree 的直径如图所示,随意一个 node 开始 bfs ,必然会找到 tree 的直径的一个端点,对这个端点进行 bfs 即可求出直径
- dfs 求直径为以下的最大值
- node 的 substree 的直径
- node 的两个最大 depth 之和
代码
class Solution {
public:
int build(vector<vector<int>>& edges) {
int n = edges.size();
vector<vector<int>> adj(n + 1);
for (auto edge : edges) {
adj[edge[0]].push_back(edge[1]);
adj[edge[1]].push_back(edge[0]);
}
vector<bool> visited(n+1);
queue<int> que;
que.push(0);
int end = 0;
visited[0] = true;
while (!que.empty()) {
end = que.front();
int size = que.size();
while (size--) {
int node = que.front(); que.pop();
for (int i = 0; i < adj[node].size(); i++) {
if (visited[adj[node][i]]) continue;
que.push(adj[node][i]);
visited[adj[node][i]] = true;
}
}
}
std::fill(visited.begin(), visited.end(), false);
que.push(end);
visited[end] = true;
int dia = 0;
while (!que.empty()) {
dia++;
int size = que.size();
while (size--) {
int node = que.front(); que.pop();
for (int i = 0; i < adj[node].size(); i++) {
if (visited[adj[node][i]]) continue;
que.push(adj[node][i]);
visited[adj[node][i]] = true;
}
}
}
return --dia;
}
int minimumDiameterAfterMerge(vector<vector<int>>& edges1, vector<vector<int>>& edges2) {
int dia_1 = build(edges1);
int dia_2 = build(edges2);
return max(dia_1/2 + dia_1%2 + dia_2/2 + dia_2 %2 + 1, max(dia_1, dia_2));
}
};