Problem: 1161. 最大层内元素和
文章目录
- 整体思路
-
-
- [1. 核心问题与功能](#1. 核心问题与功能)
- [2. 算法与逻辑步骤](#2. 算法与逻辑步骤)
-
- 完整代码
- 时空复杂度
-
-
- [1. 时间复杂度: O ( N ) O(N) O(N)](#1. 时间复杂度: O ( N ) O(N) O(N))
- [2. 空间复杂度: O ( N ) O(N) O(N)](#2. 空间复杂度: O ( N ) O(N) O(N))
-
整体思路
1. 核心问题与功能
这段代码的核心目的是找出二叉树中节点值之和最大的那一层。
- 如果有多层具有相同的最大和,根据代码逻辑(
sum > max),它返回的是层号最小的那一层。 - 输入是一个二叉树的根节点
root。 - 输出是该最大和所在的层级编号(从 1 开始计数)。
2. 算法与逻辑步骤
该解决方案采用了广度优先搜索 (BFS) ,也称为层序遍历。这是解决"层级"相关问题的最标准算法。
-
数据结构选择:
- 使用了
ArrayList作为队列 (命名为queue)来存储当前层的所有节点。 - 虽未使用标准的
LinkedList或ArrayDeque配合poll()操作,但通过每层创建一个新的ArrayList并交换引用的方式,实现了分层处理。
- 使用了
-
逻辑流程:
- 初始化 :设置
max为整数最小值(处理可能存在的负数和),ans记录结果层号,将root加入初始队列。 - 外层循环(层级迭代) :只要当前层的节点列表不为空,就继续处理。维护一个
level变量,每次循环自增。 - 内层处理(当前层计算与下一层准备) :
- 快照当前层 :将当前
queue引用赋值给temp,然后新建一个空的queue用于存放下一层的节点。 - 遍历当前层 :遍历
temp中的每个节点,累加其val到sum。 - 扩展下一层 :如果当前节点有左/右子节点,将它们加入新的
queue中。
- 快照当前层 :将当前
- 更新最大值 :当前层遍历结束后,比较
sum与max。如果sum严格大于max,则更新max并记录当前level。由于是严格大于(>),如果后续层和相等,不会更新,从而保证返回最小层号。
- 初始化 :设置
完整代码
java
/**
* Definition for a binary tree node.
* public class TreeNode {
* 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;
* }
* }
*/
class Solution {
public int maxLevelSum(TreeNode root) {
// 初始化最大和为 Integer 的最小值,防止节点值全为负数时出错
int max = Integer.MIN_VALUE;
// 用于记录产生最大和的层号
int ans = 0;
// 使用 List 作为队列,存储当前层的节点
// 这里选择 ArrayList 而不是 LinkedList,在节点数较多时访问速度可能略快,
// 但本质上都是为了实现层序遍历的临时存储
List<TreeNode> queue = new ArrayList<>();
queue.add(root);
// 开始层序遍历
// level 初始化为 1,每次循环结束 level 自增,直到队列为空(树遍历完毕)
for (int level = 1; !queue.isEmpty(); level++) {
// temp 保存当前这一层的所有节点
List<TreeNode> temp = queue;
// queue 被重新赋值为一个新的空列表,用于收集 "下一层" 的节点
// 这种写法避免了传统 BFS 中记录 size 然后 for 循环 polling 的操作
queue = new ArrayList<>();
// 用于计算当前层所有节点值的总和
int sum = 0;
// 遍历当前层的所有节点
for (TreeNode node : temp) {
// 累加节点值
sum += node.val;
// 如果左子节点存在,加入到下一层的队列中
if (node.left != null) {
queue.add(node.left);
}
// 如果右子节点存在,加入到下一层的队列中
if (node.right != null) {
queue.add(node.right);
}
}
// 核心判断逻辑:
// 如果当前层的和 sum 大于之前记录的最大和 max
// 注意这里使用的是 > 而不是 >=,这意味着如果两层和相同,
// 我们保留先出现的层(即层号较小的层),符合题目通常的要求
if (sum > max) {
max = sum; // 更新最大和
ans = level; // 更新对应的层号
}
}
// 返回具有最大元素和的最小层号
return ans;
}
}
时空复杂度
1. 时间复杂度: O ( N ) O(N) O(N)
- 计算依据 :
- 代码通过广度优先搜索(BFS)遍历整棵二叉树。
- 在
for循环和嵌套的for (TreeNode node : temp)循环中,每个节点(TreeNode)只会被访问一次,并且被加入队列一次。 - 对于每个节点,我们执行常数级别的操作:累加值、检查左右子节点、加入列表。
- 因此,总的操作次数与树中节点的总数 N N N 成正比。
- 结论 : O ( N ) O(N) O(N),其中 N N N 是二叉树的节点总数。
2. 空间复杂度: O ( N ) O(N) O(N)
- 计算依据 :
- 算法使用了额外的列表
queue(以及临时的temp)来存储节点。 - 在层序遍历中,空间消耗取决于树中最宽那一层的节点数量。
- 在最坏情况下(例如满二叉树),最后一层包含大约 N / 2 N/2 N/2 个节点。
- 因此,存储节点所需的空间与 N N N 成线性关系。
- 算法使用了额外的列表
- 结论 : O ( N ) O(N) O(N)。
- 更精确地说,是 O ( W ) O(W) O(W),其中 W W W 是树的最大宽度。但在大O表示法中,最坏情况通常视为 O ( N ) O(N) O(N)。
参考灵神