给你这棵「无向树」,请你测算并返回它的「直径」:这棵树上最长简单路径的 边数。
我们用一个由所有「边」组成的数组 edges 来表示一棵无向树,其中 edges[i] = [u, v] 表示节点 u 和 v 之间的双向边。
树上的节点都已经用 {0, 1, ..., edges.length} 中的数做了标记,每个节点上的标记都是独一无二的。
- 0 <= edges.length < 10^4
- edges[i][0] != edges[i][1]
- 0 <= edges[i][j] <= edges.length
- edges 会形成一棵无向树
本题可以用两次BFS求出
第一次BFS:随机选择一个点,求出离这个点最远的点,记为p1,此为树的直径的一个端点
第二次BFS:以p1为起点进行BFS,求出离p1距离最远的点,记为p2,此为树的直径的另一个端点,两个点之间的距离就是树的直径
具体证明可以分情况讨论,下面只讨论一种情况,其他情况可以用相同方法讨论出
设树的直径的两个端点为P1,P2
我们以X为起点进行BFS,假设求出与X距离最远的点是Y,那么距离(X, Y) > 距离(X,P1),则距离(X, Y) + 距离(X, P2) > 距离(X,P1) + 距离(X, P2),此时出现了比树的直径更长的一条路径,与先前假设矛盾,所以以X为起点进行BFS必然可以到达树的直径的一个端点,最后从一个端点进行BFS就可以求出树的直径
class Solution:
def treeDiameter(self, edges: List[List[int]]) -> int:
if len(edges) == 0:
return 0
n = len(edges) + 1 # 点的数量
g = defaultdict(list)
for i in edges:
g[i[0]].append(i[1])
g[i[1]].append(i[0])
# 1、获取距离随机选择的点最大距离的点
q = deque()
q.append(edges[0][0])
used = set()
while q:
x = q.popleft()
if x in used:
continue
if len(used) == n - 1:
point = x
break
used.add(x)
for i in g[x]:
q.append(i)
# 2、获取直径
q = deque()
q.append(point)
used = set([point])
res = -1
while q:
le = len(q)
for _ in range(le):
x = q.popleft()
for i in g[x]:
if i not in used:
used.add(i)
q.append(i)
res += 1
return res