leetcode
leetcode 251 ~ 300
二叉树的垂直遍历

二叉树的垂直遍历

难度:

标签:

题目描述

代码结果

运行时间: 23 ms, 内存: 16.1 MB


// Leetcode Problem: Vertical Order Traversal of a Binary Tree
// Using Java Stream API to solve the problem with detailed comments.
 
import java.util.*;
import java.util.stream.*;
 
class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}
 
class Solution {
    public List<List<Integer>> verticalTraversal(TreeNode root) {
        TreeMap<Integer, TreeMap<Integer, PriorityQueue<Integer>>> map = new TreeMap<>();
        traverse(root, 0, 0, map);
        return map.values().stream()
            .map(m -> m.values().stream()
                .flatMap(PriorityQueue::stream)
                .collect(Collectors.toList()))
            .collect(Collectors.toList());
    }
 
    private void traverse(TreeNode node, int x, int y, TreeMap<Integer, TreeMap<Integer, PriorityQueue<Integer>>> map) {
        if (node == null) return;
        map.putIfAbsent(x, new TreeMap<>());
        map.get(x).putIfAbsent(y, new PriorityQueue<>());
        map.get(x).get(y).add(node.val);
        traverse(node.left, x - 1, y + 1, map);
        traverse(node.right, x + 1, y + 1, map);
    }
}
 

解释

方法:

这个题解使用了BFS的思路来遍历二叉树,并用一个哈希表pos来记录每个节点的横坐标和对应的节点值。具体步骤如下: 1. 如果根节点为空,直接返回空列表。 2. 初始化一个双端队列stack,并将根节点和其横坐标0作为元组放入队列。 3. 当队列不为空时,循环执行以下操作: - 从队列左端取出一个节点p和其横坐标index。 - 将节点p的值加入哈希表pos中,键为index,值为一个列表,存储所有横坐标为index的节点值。 - 如果p的左子节点存在,将其与横坐标index-1作为元组放入队列。 - 如果p的右子节点存在,将其与横坐标index+1作为元组放入队列。 4. 遍历完成后,将哈希表pos的所有键(即横坐标)排序。 5. 按照排序后的横坐标顺序,将对应的节点值列表依次加入结果列表res中。 6. 返回结果列表res。

时间复杂度:

O(n + klogk),最坏情况下为O(nlogn)

空间复杂度:

O(n)

代码细节讲解

🦆
在二叉树的垂直遍历中,为何选择广度优先搜索(BFS)而不是深度优先搜索(DFS)?
在进行二叉树的垂直遍历时,选择广度优先搜索(BFS)主要是为了确保节点值按照从上到下的顺序被处理和收集。使用BFS可以保证一层层地遍历树节点,这样在同一垂直线上的节点,上层的总是先于下层被访问和记录,从而满足题目对顺序的要求。相比之下,深度优先搜索(DFS)可能会首先访问较深的节点,这就需要额外的逻辑来调整顺序,增加了实现的复杂度。
🦆
哈希表中键为横坐标时,如果两个节点具有相同的横坐标但不同的深度,它们的处理方式有何不同?
在此题解中,哈希表的键是节点的横坐标,而值是一个列表,这个列表按照节点被访问的顺序存储节点值。当两个节点具有相同的横坐标但位于不同的深度时,由于使用了BFS,较浅的节点会先于较深的节点被访问和加入到列表中。因此,在最终结果中,同一垂直线上的节点会按照从上到下的顺序出现,即使它们的深度不同。
🦆
在广度优先搜索遍历时,如何处理节点值的存储以确保它们按照从上到下的顺序出现?
在使用广度优先搜索遍历时,我们通过维护一个队列来控制节点的访问顺序。初始时,根节点被加入队列。在遍历过程中,每次从队列中取出一个节点,按照从左到右的顺序依次将其子节点加入队列。这样,队列始终按照从上到下,从左到右的顺序保持节点。每个节点的值被按照它们被访问的顺序加入到对应横坐标的列表中,从而保证了最终输出的垂直列表中节点值是从上到下的。
🦆
代码中对pos使用了defaultdict(list),这种数据结构带来的好处是什么?
在代码中使用defaultdict(list)作为pos的数据结构带来了几个好处:首先,它允许直接添加元素到任何未初始化的键中,这样当我们尝试向一个新的横坐标键中添加节点值时,不需要首先检查这个键是否已经存在于字典中;其次,这种结构简化了代码的编写,提高了代码的可读性和效率。例如,直接使用pos[index].append(p.val)即可添加元素,无需额外的初始化步骤。

相关问题

二叉树的层序遍历

给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

 

示例 1:

输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]

示例 2:

输入:root = [1]
输出:[[1]]

示例 3:

输入:root = []
输出:[]

 

提示:

  • 树中节点数目在范围 [0, 2000]
  • -1000 <= Node.val <= 1000