📅  最后修改于: 2023-12-03 15:12:04.442000             🧑  作者: Mango
在树结构中,我们可以定义一条路径为从根节点到某个叶子节点的所有连续边。而本题需要计算每个边在所有可能路径中的出现次数。
一条路径的定义包括许多个连续的边。我们可以观察到,对于一条路径而言,其中的每一对相邻的边(除了最后一对)都是在一个节点上共同出现的,因此我们可以考虑对每一个节点统计它所拥有的子树内所有路径中每条边的出现次数。
具体地,对于每个节点,我们可以用一个哈希表 freq
来存储它的子树内出现过的边的出现次数。而节点 $u$ 所拥有的子树则可以通过深度优先搜索(DFS)遍历而得到。在遍历子节点 $v$ 的时候,我们可以通过将节点 $v$ 内部所有边出现的次数合并到节点 $u$ 的 freq
中来完成信息的传递和合并。
具体实现时,我们可以给每一条边设定一个全局唯一的编号 $i$,然后在哈希表 freq
中,使用编号 $i$ 作为键,记录该边出现的次数。
最终对于每条边 $(u, v)$ 而言,它在所有可能路径中的出现次数就是它的两端所在节点的 freq
中记录的该边出现次数之和。
from typing import List
class Solution:
def calc_freq(self, root: int, edges: List[List[int]]) -> List[int]:
freq = {}
tree = [[] for _ in range(len(edges)+2)]
# 树的构造
for u, v in edges:
tree[u].append(v)
tree[v].append(u)
# 深度优先搜索
def dfs(u, parent):
nonlocal freq
for v in tree[u]:
if v == parent:
continue
dfs(v, u)
for k, value in freq.get(v, {}).items():
freq[u][k] = freq[u].get(k, 0) + value
for v in tree[u]:
if v == parent:
continue
edge_id1 = min(u, v)*len(edges) + max(u, v)
freq[u][edge_id1] = freq[u].get(edge_id1, 0) + 1
freq[v][edge_id1] = freq[v].get(edge_id1, 0) + 1
dfs(root, -1)
# 计算边出现的次数
res = [0 for _ in range(len(edges))]
for u, v in edges:
edge_id = min(u, v)*len(edges) + max(u, v)
res[edge_id - 1] = freq[u].get(edge_id, 0) + freq[v].get(edge_id, 0)
return res
时间复杂度:$\mathcal{O}(n)$,其中 $n$ 为节点数。在深度优先搜索中,我们需要遍历所有节点各一次,因此总时间复杂度为 $\mathcal{O}(n)$。
空间复杂度:$\mathcal{O}(n)$,其中 $n$ 为节点数。哈希表 freq
最坏情况下需要记录每一条边的出现次数,因此空间复杂度为 $\mathcal{O}(m)$,其中 $m$ 为边数。由于一棵 $n$ 个节点的树一定有 $n-1$ 条边,因此空间复杂度为 $\mathcal{O}(n)$。
本题是一道树结构的基础计算题目。通过合理地设计哈希表,并使用深度优先搜索算法可达到线性时间复杂度的解题效果。