统计值等于子树平均值的节点数
难度:
标签:
题目描述
给你一棵二叉树的根节点 root
,找出并返回满足要求的节点数,要求节点的值等于其 子树 中值的 平均值 。
注意:
n
个元素的平均值可以由n
个元素 求和 然后再除以n
,并 向下舍入 到最近的整数。root
的 子树 由root
和它的所有后代组成。
示例 1:

输入:root = [4,8,5,0,1,null,6] 输出:5 解释: 对值为 4 的节点:子树的平均值 (4 + 8 + 5 + 0 + 1 + 6) / 6 = 24 / 6 = 4 。 对值为 5 的节点:子树的平均值 (5 + 6) / 2 = 11 / 2 = 5 。 对值为 0 的节点:子树的平均值 0 / 1 = 0 。 对值为 1 的节点:子树的平均值 1 / 1 = 1 。 对值为 6 的节点:子树的平均值 6 / 1 = 6 。
示例 2:

输入:root = [1] 输出:1 解释:对值为 1 的节点:子树的平均值 1 / 1 = 1。
提示:
- 树中节点数目在范围
[1, 1000]
内 0 <= Node.val <= 1000
代码结果
运行时间: 28 ms, 内存: 16.9 MB
/*
题目思路:
1. 使用流式处理需要重写树的遍历方式,使其能支持流操作。
2. 先将树的所有节点放入一个列表中。
3. 遍历列表计算每个节点的子树和并判断是否满足条件。
*/
import java.util.*;
import java.util.stream.*;
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
class Solution {
public int averageOfSubtree(TreeNode root) {
List<TreeNode> nodes = new ArrayList<>();
traverse(root, nodes);
return (int) nodes.stream()
.filter(node -> node.val == sumAndCount(node)[0] / sumAndCount(node)[1])
.count();
}
private void traverse(TreeNode node, List<TreeNode> nodes) {
if (node != null) {
nodes.add(node);
traverse(node.left, nodes);
traverse(node.right, nodes);
}
}
private int[] sumAndCount(TreeNode node) {
if (node == null) {
return new int[]{0, 0};
}
int[] left = sumAndCount(node.left);
int[] right = sumAndCount(node.right);
int sum = left[0] + right[0] + node.val;
int count = left[1] + right[1] + 1;
return new int[]{sum, count};
}
}
解释
方法:
该题解采用了递归的方式进行深度优先搜索(DFS)。对于每个节点,首先递归计算其左右子树内所有节点的值的和以及节点个数。然后,将当前节点的值加到子树的和中,并将节点个数加一,从而获取包括当前节点在内的整个子树的总和和节点个数。接着,计算子树的平均值并向下取整,如果这个值等于当前节点的值,则结果计数器增加。最后,函数返回当前子树的节点数量和值的总和,以供上层节点的计算。
时间复杂度:
O(n)
空间复杂度:
O(n) in the worst case, O(log(n)) in average case for balanced trees
代码细节讲解
🦆
在计算节点平均值时,你是如何确保结果总是正确向下舍入的?
▷🦆
你的解决方案在遇到一个节点值非常大,可能导致整数溢出时,有什么应对策略吗?
▷🦆
在递归函数中,当节点为空时直接返回(0, 0),这种设计是否考虑了所有可能的边界情况?
▷🦆
代码中使用了非局部变量`res`,这种设计方式有什么优点和潜在的缺点?
▷