LeetCode 题解工作台

树中每个节点放置的金币数目

给你一棵 n 个节点的 无向 树,节点编号为 0 到 n - 1 ,树的根节点在节点 0 处。同时给你一个长度为 n - 1 的二维整数数组 edges ,其中 edges[i] = [a i , b i ] 表示树中节点 a i 和 b i 之间有一条边。 给你一个长度为 n 下标从 0 开始的整…

category

5

题型

code_blocks

5

代码语言

hub

3

相关题

当前训练重点

困难 · 二分·树·traversal

bolt

答案摘要

根据题目描述,每个节点 的放置的金币数有两种情况: - 如果节点 对应的子树中的节点数目小于 ,那么放 个金币;

Interview AiBox logo

Interview AiBox 实时 AI 助手,陪你讲清 二分·树·traversal 题型思路

试试 AiBox 面试助手arrow_forward
description

题目描述

给你一棵 n 个节点的 无向 树,节点编号为 0 到 n - 1 ,树的根节点在节点 0 处。同时给你一个长度为 n - 1 的二维整数数组 edges ,其中 edges[i] = [ai, bi] 表示树中节点 ai 和 bi 之间有一条边。

给你一个长度为 n 下标从 0 开始的整数数组 cost ,其中 cost[i] 是第 i 个节点的 开销 。

你需要在树中每个节点都放置金币,在节点 i 处的金币数目计算方法如下:

  • 如果节点 i 对应的子树中的节点数目小于 3 ,那么放 1 个金币。
  • 否则,计算节点 i 对应的子树内 3 个不同节点的开销乘积的 最大值 ,并在节点 i 处放置对应数目的金币。如果最大乘积是 负数 ,那么放置 0 个金币。

请你返回一个长度为 n 的数组 coin ,coin[i]是节点 i 处的金币数目。

 

示例 1:

输入:edges = [[0,1],[0,2],[0,3],[0,4],[0,5]], cost = [1,2,3,4,5,6]
输出:[120,1,1,1,1,1]
解释:在节点 0 处放置 6 * 5 * 4 = 120 个金币。所有其他节点都是叶子节点,子树中只有 1 个节点,所以其他每个节点都放 1 个金币。

示例 2:

输入:edges = [[0,1],[0,2],[1,3],[1,4],[1,5],[2,6],[2,7],[2,8]], cost = [1,4,2,3,5,7,8,-4,2]
输出:[280,140,32,1,1,1,1,1,1]
解释:每个节点放置的金币数分别为:
- 节点 0 处放置 8 * 7 * 5 = 280 个金币。
- 节点 1 处放置 7 * 5 * 4 = 140 个金币。
- 节点 2 处放置 8 * 2 * 2 = 32 个金币。
- 其他节点都是叶子节点,子树内节点数目为 1 ,所以其他每个节点都放 1 个金币。

示例 3:

输入:edges = [[0,1],[0,2]], cost = [1,2,-2]
输出:[0,1,1]
解释:节点 1 和 2 都是叶子节点,子树内节点数目为 1 ,各放置 1 个金币。节点 0 处唯一的开销乘积是 2 * 1 * -2 = -4 。所以在节点 0 处放置 0 个金币。

 

提示:

  • 2 <= n <= 2 * 104
  • edges.length == n - 1
  • edges[i].length == 2
  • 0 <= ai, bi < n
  • cost.length == n
  • 1 <= |cost[i]| <= 104
  • edges 一定是一棵合法的树。
lightbulb

解题思路

方法一:DFS + 排序

根据题目描述,每个节点 aa 的放置的金币数有两种情况:

  • 如果节点 aa 对应的子树中的节点数目小于 33,那么放 11 个金币;
  • 如果节点 aa 对应的子树中的节点数目大于等于 33,那么我们需要取出子树中的 33 个不同节点,计算它们的开销乘积的最大值,然后在节点 aa 处放置对应数目的金币,如果最大乘积是负数,那么放置 00 个金币。

第一种情况比较简单,我们只需要在遍历的过程中,统计每个节点的子树中的节点数目即可。

而对于第二种情况,如果开销都是正数,那么应该取开销最大的 33 个节点;如果开销中有负数,那么应该取开销最小的 22 个节点和开销最大的 11 个节点。因此,我们需要维护每个子树最小的 22 个开销和最大的 33 个开销。

我们先根据题目给定的二维数组 edgesedges 构建邻接表 gg,其中 g[a]g[a] 表示节点 aa 的所有邻居节点。

接下来,我们设计一个函数 dfs(a,fa)dfs(a, fa),该函数返回一个数组 resres,其中存储了节点 aa 的子树中最小的 22 个开销和最大的 33 个开销(可能不足 55 个)。

在函数 dfs(a,fa)dfs(a, fa) 中,我们将节点 aa 的开销 cost[a]cost[a] 加入数组 resres 中,然后遍历节点 aa 的所有邻居节点 bb,如果 bb 不是节点 aa 的父节点 fafa,那么我们将 dfs(b,a)dfs(b, a) 的结果加入数组 resres 中。

然后,我们对数组 resres 进行排序,然后根据数组 resres 的长度 mm 计算节点 aa 的放置金币数目,更新 ans[a]ans[a]

  • 如果 m3m \ge 3,那么节点 aa 的放置金币数目为 max(0,res[m1]×res[m2]×res[m3],res[0]×res[1]×res[m1])\max(0, res[m - 1] \times res[m - 2] \times res[m - 3], res[0] \times res[1] \times res[m - 1]),否则节点 aa 的放置金币数目为 11
  • 如果 m>5m > 5,那么我们只需要保留数组 resres 的前 22 个元素和后 33 个元素。

最后,我们调用函数 dfs(0,1)dfs(0, -1),并且返回答案数组 ansans 即可。

时间复杂度 O(n×logn)O(n \times \log n),空间复杂度 O(n)O(n)。其中 nn 是节点的数目。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution:
    def placedCoins(self, edges: List[List[int]], cost: List[int]) -> List[int]:
        def dfs(a: int, fa: int) -> List[int]:
            res = [cost[a]]
            for b in g[a]:
                if b != fa:
                    res.extend(dfs(b, a))
            res.sort()
            if len(res) >= 3:
                ans[a] = max(res[-3] * res[-2] * res[-1], res[0] * res[1] * res[-1], 0)
            if len(res) > 5:
                res = res[:2] + res[-3:]
            return res

        n = len(cost)
        g = [[] for _ in range(n)]
        for a, b in edges:
            g[a].append(b)
            g[b].append(a)
        ans = [1] * n
        dfs(0, -1)
        return ans
speed

复杂度分析

指标
时间complexity is O(n) for traversing all nodes once with DFS and aggregating subtree costs. Space complexity is O(n) for storing children and cost tracking arrays in each node's state during traversal.
空间Depends on the final approach
psychology

面试官常问的追问

外企场景
  • question_mark

    Candidate considers DFS for full tree traversal and subtree aggregation.

  • question_mark

    Candidate identifies that leaf nodes always receive one coin as a base case.

  • question_mark

    Candidate correctly handles negative and zero costs in product calculation to avoid incorrect coin counts.

warning

常见陷阱

外企场景
  • error

    Forgetting to handle negative and zero costs leading to wrong coin numbers.

  • error

    Incorrectly tracking fewer than three largest/smallest costs, causing wrong product computation.

  • error

    Failing to store subtree results, resulting in repeated calculations and timeouts on large trees.

swap_horiz

进阶变体

外企场景
  • arrow_right_alt

    Compute coins using sum instead of product of subtree costs.

  • arrow_right_alt

    Find maximum coin placement in weighted n-ary trees instead of binary trees.

  • arrow_right_alt

    Determine minimum coins with modified rules for negative-only subtrees.

help

常见问题

外企场景

树中每个节点放置的金币数目题解:二分·树·traversal | LeetCode #2973 困难