某程序员爆料:没买房被组长针对了,他自己的房估计亏了五百万,现在对我总阴阳怪气,说我不买房干嘛,还说我的存款就算。。
刚看到个贴子,说有程序员吐槽自己没买房被组长疯狂针对。组长房子自己亏了五百万,现在见谁都要劝一句“你咋还不买房”“背星毕业都不怕”。这画风是真熟悉。
我觉得这事吧,问题根本不在房子,而在情绪迁怒。亏钱是他的事,可他把气撒到同事身上,这就有点离谱了。
从职场的角度看,一个人成熟不成熟,看他能不能把情绪和工作分开。你房子套牢了,那是投资判断;你阴阳同事,那就是职业素养问题。再说了,别人买不买房、存了多少钱,跟你绩效一毛钱关系都没有。
不过话说回来,这种情况下别硬刚,保持边界就行。
他阴阳你,你就当背景噪音,专心干自己的活。说到底,职场不是比谁嘴碎,而是比谁更能提供价值。
面试题:二叉树的层平均值
先说结论:这道「二叉树的层平均值」本质就是一层一层地遍历二叉树,把每一层所有节点的值加起来,再除以这一层的节点个数,最后按层顺序返回一个平均值列表就好了。
题目大意是这样的:
给你一棵二叉树,树里每个节点有一个整数值。 你要返回一个数组 / 列表,第 i 个元素是第 i 层所有节点值的平均数。
举个小例子,假设树长这样:
3
/ \
9 20
/ \
15 7
那各层是:
第 0 层: [3],平均值 3.0 第 1 层: [9, 20],平均值 (9 + 20) / 2 = 14.5 第 2 层: [15, 7],平均值 (15 + 7) / 2 = 11.0
结果就是 [3.0, 14.5, 11.0]。
自然想到的解法:层序遍历 + 统计
只要你做过「二叉树的层序遍历」(也就是 BFS,从上往下一层层扫),这题基本就已经解决一半了。
核心思路:
用一个队列
Queue<TreeNode>,先把根节点root丢进去。每次从队列里「拿出当前这一层」所有节点:
如果它有左孩子,就把左孩子入队; 如果它有右孩子,就把右孩子入队。
先记下当前队列的大小
size,这就是这一层有多少个节点。循环
size次: 每次弹出一个节点,把它的值加到当层的sum里。
这一层处理完之后,用 sum / size 算出平均值,丢进结果列表。
队列清空,说明树遍历完了。
注意两个细节:
平均值要用 double来存,不要用整型(不然会被整除)。sum的类型用double或long都可以,我习惯用double,少一步强转。
先来个常规的 TreeNode 定义:
publicclassTreeNode{
int val;
TreeNode left;
TreeNode right;
TreeNode() {}
TreeNode(int val) {
this.val = val;
}
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
然后是主方法:
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
publicclassSolution{
public List<Double> averageOfLevels(TreeNode root){
List<Double> res = new ArrayList<>();
if (root == null) {
return res;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
int size = queue.size(); // 当前层节点数
double sum = 0.0; // 当前层节点值之和
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
sum += node.val;
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
}
res.add(sum / size);
}
return res;
}
}
这段逻辑对应上面的思路非常直接:
while (!queue.isEmpty()):一层一层往下走;int size = queue.size():当前层有多少个节点,就循环多少次;每层结束后 res.add(sum / size):记录这一层的平均值。
再说一个 DFS 解法(顺便拓宽一下思路)
虽然 BFS 写起来最顺手,不过也可以用 DFS 做: 思路是「前序遍历」整棵树,同时维护两个数组 / 列表:
levelSum[level]:第level层所有节点值的和levelCount[level]:第level层节点数量
遍历的时候,把当前节点的值加到对应层的 sum 上,同时 count + 1。 遍历结束后,再逐层用 sum / count 算平均值。
Java 写起来像这样:
import java.util.ArrayList;
import java.util.List;
publicclassSolutionDFS{
private List<Double> levelSum = new ArrayList<>();
private List<Integer> levelCount = new ArrayList<>();
public List<Double> averageOfLevels(TreeNode root){
dfs(root, 0);
List<Double> res = new ArrayList<>();
for (int i = 0; i < levelSum.size(); i++) {
res.add(levelSum.get(i) / levelCount.get(i));
}
return res;
}
privatevoiddfs(TreeNode node, int level){
if (node == null) {
return;
}
// 还没有这个层级,先初始化
if (level == levelSum.size()) {
levelSum.add(0.0);
levelCount.add(0);
}
// 更新这一层的 sum 和 count
levelSum.set(level, levelSum.get(level) + node.val);
levelCount.set(level, levelCount.get(level) + 1);
dfs(node.left, level + 1);
dfs(node.right, level + 1);
}
}
这个方式比 BFS 稍微绕一点,但是能帮你熟悉「递归里带着层级信息」这种套路,很多树相关题目都会用到。
复杂度简单算一下
不管是 BFS 还是 DFS:
每个节点只会访问一次,所以时间复杂度都是 **O(n)**,
n是节点总数。额外空间:
BFS:队列最坏情况下会装下某一层全部节点,空间复杂度是 **O(width)**, width是树的最大宽度。DFS:递归深度最多是树的高度,空间复杂度是 **O(height)**,另外还要存每一层的 sum 和 count。
整体来说,这题属于那种「会层序遍历就能做」的题,非常适合用来熟悉二叉树 BFS 的模板写法。你可以先把 BFS 版本默写几遍,确保自己在任何时候都能写出来,再顺手把 DFS 版本也敲一遍,当作加餐训练。
-END-
我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html