LC 100318. 合并两棵树后的最小直径
https://leetcode.cn/problems/find-minimum-diameter-after-merging-two-trees/description/
这题需要针对每个树分别求解两个东西:
- 这个树的本身的直径,就是任意两个点的最远距离,假设是 D
- 这个树的半径的最小值。如果以X为根的话,就是X到任意点的最大距离,假设是M
那么结果就是 \(max(D0, D1, M0 + M1 + 1)\) . D这个值比较好求解,M这个值求解就稍微需要点工作:
- 假设假设我们从0这个点开始遍历,遍历到了x这个点,并且我们维持一个d0,这个值表示x向外(非x的子树)的点可以到达的最远距离。
- 那么以x为根的半径就是 \(max(d0, depth[x])\), 其中 \(depth[x]\) 表示x为根的子树的最大高度。
- 让我们继续遍历x的子节点y的时候,按照如下更新 d0
- 如果y不是在 \(depth[x]\) 最长路径上的话,那么 \(d0 = max(d0 + 1, depth[x] + 1)\)
- 如果y在最长路径的话,那么就要取第二个最长的路径。
class Solution:
def minimumDiameterAfterMerge(self, edges1: List[List[int]], edges2: List[List[int]]) -> int:
def find(edges):
n = len(edges) + 1
if n == 1: return 0, 0
adj = [[] for _ in range(n)]
for x, y in edges:
adj[x].append(y)
adj[y].append(x)
depth = [[] for _ in range(n)]
def search(x, p):
# return tree_depth, max_dist
if len(adj[x]) == 1 and adj[x][0] == p:
return 0, 0
res = 0
for y in adj[x]:
if y == p: continue
td, md = search(y, x)
depth[x].append((y, td + 1))
res = max(res, md)
depth[x].sort(key=lambda x: x[1])
d = depth[x]
if len(d) >= 2:
res = max(res, d[-1][1] + d[-2][1])
res = max(res, d[-1][1])
return d[-1][1], res
_, max_dist = search(0, -1)
# print(depth)
def dfs(x, p, d0):
if len(adj[x]) == 1 and adj[x][0] == p:
return d0
d = depth[x]
ans = max(d[-1][1], d0)
for y in adj[x]:
if y == p: continue
d1 = d[-1][1]
if y == d[-1][0]:
if len(d) >= 2:
d1 = d[-2][1]
else:
d1 = 0
# 从x遍历到y, y为分界点, Y的到其他点的最大距离有
# 1. y 通过 x 之前的节点到达其他节点最大距离是 d0 + 1
# 2. y 通过 x 到达其他节点最大距离是 d1 + 1
r = dfs(y, x, max(d0 + 1, d1 + 1))
ans = min(r, ans)
return ans
rad = dfs(0, -1, 0)
return rad, max_dist
r0, d0 = find(edges1)
r1, d1 = find(edges2)
# print(r0, d0, r1, d1)
return max(r0 + r1 + 1, d0, d1)