leetcode
leetcode 451 ~ 500
在每个树行中找最大值

在每个树行中找最大值

难度:

标签:

题目描述

给定一棵二叉树的根节点 root ,请找出该二叉树中每一层的最大值。

 

示例1:

输入: root = [1,3,2,5,3,null,9]
输出: [1,3,9]

示例2:

输入: root = [1,2,3]
输出: [1,3]

 

提示:

  • 二叉树的节点个数的范围是 [0,104]
  • -231 <= Node.val <= 231 - 1

 

代码结果

运行时间: 24 ms, 内存: 18.8 MB


/*
 * 题目思路:
 * 使用Java Stream实现,先用广度优先搜索(BFS)
 * 收集每一层的节点,再计算最大值。
 */
import java.util.*;
import java.util.stream.*;
 
public class Solution {
    public List<Integer> largestValues(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if (root == null) return result;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            List<TreeNode> level = new ArrayList<>();
            while (!queue.isEmpty()) level.add(queue.poll());
            result.add(level.stream().mapToInt(node -> node.val).max().orElse(Integer.MIN_VALUE));
            level.forEach(node -> {
                if (node.left != null) queue.offer(node.left);
                if (node.right != null) queue.offer(node.right);
            });
        }
        return result;
    }
}
 
class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}

解释

方法:

这个题解采用深度优先搜索(DFS)的思路。它从根节点开始递归地遍历整棵树,同时跟踪当前节点所在的层高(h)。在每个递归步骤中,如果当前层高大于等于结果列表 ans 的长度,就将当前节点的值加入 ans。否则,比较当前节点的值与 ans 中对应层高的最大值,取较大者更新 ans。然后递归地处理当前节点的左右子树,层高 h 加 1。最后返回 ans,即每一层的最大值列表。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
在DFS递归过程中,如果遇到一个节点的值为null,代码中是如何处理这种情况的?
在题解中提供的DFS递归逻辑里,递归函数`dfs`是从根节点开始调用,并在函数内部检查`if root:`来判断当前节点是否为null。如果`root`为null,则当前递归调用不会执行任何操作,直接返回,因此不会有null值的节点被处理或导致错误。这种方式有效地避免了null节点引起的问题。
🦆
给定的答案中提到,将节点值与ans中对应层的最大值进行比较,如果ans[h]已经是该层的最大值,为何还需要再次对其进行比较和更新?
虽然ans[h]可能已经记录了之前访问过的节点中的最大值,但是在继续DFS过程中,我们仍然需要考虑当前层后续节点的值可能更大的情况。因此,每次访问一个新节点时,都需要将其值与ans[h]进行比较,并在必要时更新ans[h],以确保能够正确地记录每一层的最大值。这是确保结果正确性的必要步骤。
🦆
DFS递归的终止条件是什么?在代码中如何确保每个节点都仅被访问一次?
题解中的DFS递归的终止条件是当前访问的节点为null,即在递归函数`dfs`的开始通过`if root:`判断来实现。如果节点为null,递归不再继续向下执行。此外,每个节点仅被访问一次是通过递归调用的机制保证的,即每个节点在递归中只会被处理一次,分别在其左右子节点之后。这样的调用顺序确保了每个节点只被访问一次。
🦆
题解中使用了列表ans来记录每一层的最大值,为什么选择使用列表而不是其他数据结构,如字典?
在这个特定的问题中,使用列表来记录每一层的最大值是因为每层的索引(层高h)是一个从0开始的连续整数,这使得列表成为一个非常适合的选择,因为可以直接使用层高作为索引进行访问和更新操作。列表相比字典在这种情况下有更好的空间和时间效率,因为它直接支持按索引访问,而不需要额外的键查找开销。

相关问题