mirror of
https://github.com/halfrost/LeetCode-Go.git
synced 2025-07-06 01:15:57 +08:00
53 lines
2.4 KiB
Go
53 lines
2.4 KiB
Go
package leetcode
|
||
|
||
func sumOfDistancesInTree(N int, edges [][]int) []int {
|
||
// count[i] 中存储的是以 i 为根节点,所有子树结点和根节点的总数
|
||
tree, visited, count, res := make([][]int, N), make([]bool, N), make([]int, N), make([]int, N)
|
||
for _, e := range edges {
|
||
i, j := e[0], e[1]
|
||
tree[i] = append(tree[i], j)
|
||
tree[j] = append(tree[j], i)
|
||
}
|
||
deepFirstSearch(0, visited, count, res, tree)
|
||
// 重置访问状态,再进行一次 DFS
|
||
visited = make([]bool, N)
|
||
// 进入第二次 DFS 之前,只有 res[0] 里面存的是正确的值,因为第一次 DFS 计算出了以 0 为根节点的所有路径和
|
||
// 第二次 DFS 的目的是把以 0 为根节点的路径和转换成以 n 为根节点的路径和
|
||
deepSecondSearch(0, visited, count, res, tree)
|
||
|
||
return res
|
||
}
|
||
|
||
func deepFirstSearch(root int, visited []bool, count, res []int, tree [][]int) {
|
||
visited[root] = true
|
||
for _, n := range tree[root] {
|
||
if visited[n] {
|
||
continue
|
||
}
|
||
deepFirstSearch(n, visited, count, res, tree)
|
||
count[root] += count[n]
|
||
// root 节点到 n 的所有路径和 = 以 n 为根节点到所有子树的路径和 res[n] + root 到 count[n] 中每个节点的个数(root 节点和以 n 为根节点的每个节点都增加一条路径)
|
||
// root 节点和以 n 为根节点的每个节点都增加一条路径 = 以 n 为根节点,子树节点数和根节点数的总和,即 count[n]
|
||
res[root] += res[n] + count[n]
|
||
}
|
||
count[root]++
|
||
}
|
||
|
||
// 从 root 开始,把 root 节点的子节点,依次设置成新的根节点
|
||
func deepSecondSearch(root int, visited []bool, count, res []int, tree [][]int) {
|
||
N := len(visited)
|
||
visited[root] = true
|
||
for _, n := range tree[root] {
|
||
if visited[n] {
|
||
continue
|
||
}
|
||
// 根节点从 root 变成 n 后
|
||
// res[root] 存储的是以 root 为根节点到所有节点的路径总长度
|
||
// 1. root 到 n 节点增加的路径长度 = root 节点和以 n 为根节点的每个节点都增加一条路径 = 以 n 为根节点,子树节点数和根节点数的总和,即 count[n]
|
||
// 2. n 到以 n 为根节点的所有子树节点以外的节点增加的路径长度 = n 节点和非 n 为根节点子树的每个节点都增加一条路径 = N - count[n]
|
||
// 所以把根节点从 root 转移到 n,需要增加的路径是上面👆第二步计算的,需要减少的路径是上面👆第一步计算的
|
||
res[n] = res[root] + (N - count[n]) - count[n]
|
||
deepSecondSearch(n, visited, count, res, tree)
|
||
}
|
||
}
|