LeetCode 题解工作台
在树上执行操作以后得到的最大分数
有一棵 n 个节点的无向树,节点编号为 0 到 n - 1 ,根节点编号为 0 。给你一个长度为 n - 1 的二维整数数组 edges 表示这棵树,其中 edges[i] = [a i , b i ] 表示树中节点 a i 和 b i 有一条边。 同时给你一个长度为 n 下标从 0 开始的整数数组…
3
题型
5
代码语言
3
相关题
当前训练重点
中等 · 二分·树·traversal
答案摘要
题目实际上是让我们从树的所有节点中选出一些节点,使得这些节点的值之和最大,并且每条从根节点到叶子节点的路径上都有一个点没有被选中。 我们可以使用树形 DP 的方法解决这个问题。
Interview AiBoxInterview AiBox 实时 AI 助手,陪你讲清 二分·树·traversal 题型思路
题目描述
有一棵 n 个节点的无向树,节点编号为 0 到 n - 1 ,根节点编号为 0 。给你一个长度为 n - 1 的二维整数数组 edges 表示这棵树,其中 edges[i] = [ai, bi] 表示树中节点 ai 和 bi 有一条边。
同时给你一个长度为 n 下标从 0 开始的整数数组 values ,其中 values[i] 表示第 i 个节点的值。
一开始你的分数为 0 ,每次操作中,你将执行:
- 选择节点
i。 - 将
values[i]加入你的分数。 - 将
values[i]变为0。
如果从根节点出发,到任意叶子节点经过的路径上的节点值之和都不等于 0 ,那么我们称这棵树是 健康的 。
你可以对这棵树执行任意次操作,但要求执行完所有操作以后树是 健康的 ,请你返回你可以获得的 最大分数 。
示例 1:

输入:edges = [[0,1],[0,2],[0,3],[2,4],[4,5]], values = [5,2,5,2,1,1] 输出:11 解释:我们可以选择节点 1 ,2 ,3 ,4 和 5 。根节点的值是非 0 的。所以从根出发到任意叶子节点路径上节点值之和都不为 0 。所以树是健康的。你的得分之和为 values[1] + values[2] + values[3] + values[4] + values[5] = 11 。 11 是你对树执行任意次操作以后可以获得的最大得分之和。
示例 2:

输入:edges = [[0,1],[0,2],[1,3],[1,4],[2,5],[2,6]], values = [20,10,9,7,4,3,5] 输出:40 解释:我们选择节点 0 ,2 ,3 和 4 。 - 从 0 到 4 的节点值之和为 10 。 - 从 0 到 3 的节点值之和为 10 。 - 从 0 到 5 的节点值之和为 3 。 - 从 0 到 6 的节点值之和为 5 。 所以树是健康的。你的得分之和为 values[0] + values[2] + values[3] + values[4] = 40 。 40 是你对树执行任意次操作以后可以获得的最大得分之和。
提示:
2 <= n <= 2 * 104edges.length == n - 1edges[i].length == 20 <= ai, bi < nvalues.length == n1 <= values[i] <= 109- 输入保证
edges构成一棵合法的树。
解题思路
方法一:树形 DP
题目实际上是让我们从树的所有节点中选出一些节点,使得这些节点的值之和最大,并且每条从根节点到叶子节点的路径上都有一个点没有被选中。
我们可以使用树形 DP 的方法解决这个问题。
我们设计一个函数 ,其中 表示当前以节点 作为子树的根节点,且 表示 的父节点,函数返回一个长度为 的数组,其中 表示该子树中所有节点的值之和,而 表示该子树满足每条路径上都有一个点没有被选中的最大值。
其中 的值可以直接通过 DFS 累加每个节点的值得到,而 的值,则需要考虑两种情况,即节点 是否被选中。如果被选中,那么节点 的每个子树得必须满足每条路径上都有一个点没有被选中;如果没有被选中,那么节点 的每个子树可以选取所有节点。我们取这两种情况中的最大值即可。
需要注意的是,叶子节点的 的值为 ,因为叶子节点没有子树,所以不需要考虑每条路径上都有一个点没有被选中的情况。
答案为 。
时间复杂度 ,空间复杂度 。其中 为节点数。
class Solution:
def maximumScoreAfterOperations(
self, edges: List[List[int]], values: List[int]
) -> int:
def dfs(i: int, fa: int = -1) -> (int, int):
a = b = 0
leaf = True
for j in g[i]:
if j != fa:
leaf = False
aa, bb = dfs(j, i)
a += aa
b += bb
if leaf:
return values[i], 0
return values[i] + a, max(values[i] + b, a)
g = [[] for _ in range(len(values))]
for a, b in edges:
g[a].append(b)
g[b].append(a)
return dfs(0)[1]
复杂度分析
| 指标 | 值 |
|---|---|
| 时间 | Depends on the final approach |
| 空间 | Depends on the final approach |
面试官常问的追问
外企场景- question_mark
They want you to convert a global healthy-path rule into a local subtree DP state.
- question_mark
They expect you to notice that maximizing score is equivalent to minimizing the value that must remain.
- question_mark
They are testing whether you can write a parent-aware DFS on an undirected tree without revisiting nodes.
常见陷阱
外企场景- error
Treating this as a greedy pick-the-largest-values problem and breaking a leaf path by removing its only remaining value.
- error
Using the wrong base case for leaves; dp[leaf] is values[leaf], not 0.
- error
Forgetting that the graph is undirected and recursing back to the parent, which corrupts subtree sums and causes cycles.
进阶变体
外企场景- arrow_right_alt
Return the minimum value that must remain instead of the maximum score; that is exactly dp[0].
- arrow_right_alt
Change the healthy rule so every root-to-leaf path must stay at least K, which would alter the subtree state and transition.
- arrow_right_alt
Ask for an iterative postorder traversal version to avoid recursion depth concerns on a long chain tree.