1273. 删除树节点
大约 4 分钟
--- 
1273. 删除树节点
- 标签:树、深度优先搜索、广度优先搜索、数组
- 难度:中等
题目链接
题目大意
描述:给你一棵以节点 为根节点的树,定义如下:
- 节点的总数为 个。
- 第 个节点的值为 。
- 第 个节点的父节点是 ()。
你需要删除节点值之和为 的每一棵子树。在完成所有删除之后,返回树中剩余节点的数目。
要求:返回剩余节点的数目。
说明:
- 。
- 。
- 。
- 表示节点 是树的根。
- 。
- 。
- 题目输入数据保证是一棵有效的树。
示例:
- 示例 1:

输入:nodes = 7, parent = [-1,0,0,1,2,2,2], value = [1,-2,4,0,-2,-1,-1]
输出:2- 示例 2:
输入:nodes = 7, parent = [-1,0,0,1,2,2,2], value = [1,-2,4,0,-2,-1,-2]
输出:6解题思路
思路 1:后序遍历(DFS)
1. 核心思想
删除和为 的子树:如果一棵子树的所有节点值加起来等于 ,就把这棵子树整个砍掉。
关键问题是处理顺序:删除一个子树时,它的子节点可能已经被删除了吗?不能。我们必须先知道子树的完整和才能判断它是否该被删除。所以需要从叶子节点向上计算——这正好是树的后序遍历(先处理子节点,再处理父节点)。
后序遍历的顺序保证了:一个节点的所有子节点都被处理完之后,我们才处理该节点本身。这样就能正确地递归判断。
2. 具体步骤
第 1 步:建图
根据 数组构建每个节点的子节点列表 。根节点 的父节点是 ,其余节点 的父节点是 ,所以将 添加到 中。
第 2 步:后序遍历
定义递归函数 ,返回两个值:
- :以 为根的子树中所有节点的值之和(删除操作之前)。
- :以 为根的子树中经过删除后剩余节点的个数。
递归过程:
- 初始化 ,。
- 遍历 的所有子节点 ,递归调用 ,将返回的子树和与剩余节点数累加到 和 中。
- 处理完所有子节点后,如果 ,说明整棵子树和为 ,应该全部删除,返回 。
- 否则返回 。
第 3 步:返回结果
根节点的 返回的剩余节点数就是答案。
结合示例 1 走一遍:
建树:
- 节点 的子节点:
- 节点 的子节点:
- 节点 的子节点:
后序遍历:
- :, → 返回 (节点 被删除)
- :,加上子节点 的 ,,不删除 → 返回
- : → 返回
- : → 返回
- : → 返回
- :,加上子节点 的 , → 返回 (以 为根的整棵子树被删除)
- :,加上子节点 的 和子节点 的 ,, → 返回
最终剩余 个节点。
思路 1:代码
class Solution:
def deleteTreeNodes(self, nodes: int, parent: List[int], value: List[int]) -> int:
# 第 1 步:构建子节点列表
children = [[] for _ in range(nodes)]
for i in range(1, nodes):
children[parent[i]].append(i)
# 第 2 步:后序遍历,返回 (子树和, 剩余节点数)
def dfs(u):
total_sum = value[u]
total_cnt = 1
# 先递归处理所有子节点
for v in children[u]:
child_sum, child_cnt = dfs(v)
total_sum += child_sum
total_cnt += child_cnt
# 如果整棵子树和为 0,全部删除
if total_sum == 0:
return (0, 0)
return (total_sum, total_cnt)
# 第 3 步:从根节点开始
return dfs(0)[1]思路 1:复杂度分析
- 时间复杂度:,每个节点恰好被访问一次,后序遍历的总时间与节点数成正比。
- 空间复杂度:,递归栈的深度在最坏情况下(树退化为链)为 。同时需要 数组存储每个节点的子节点列表,总大小也是 。