LeetCode偶尔一题 —— 314. 二叉树的垂直遍历

562 阅读2分钟

原题地址:https://leetcode-cn.com/problems/binary-tree-vertical-order-traversal/
原文链接:https://juejin.cn/post/6873108574982111239

题目

给定一个二叉树,返回其结点 垂直方向(从上到下,逐列)遍历的值。

如果两个结点在同一行和列,那么顺序则为 从左到右。

示例 1:

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

   3
  /\
 /  \
9   20
    /\
   /  \
  15   7 

输出:

[
  [9],
  [3,15],
  [20],
  [7]
]

示例 2:

输入: [3,9,8,4,0,1,7]

     3
    /\
   /  \
  9    8
  /\   /\
 /  \ /  \
4   0 1   7 

输出:

[
  [4],
  [9],
  [3,0,1],
  [8],
  [7]
]

示例 3:

输入: [3,9,8,4,0,1,7,null,null,null,2,5](注意:0 的右侧子节点为 21 的左侧子节点为 53
    /\
   /  \
   9   8
  /\  /\
 /  \/  \
 4  01   7
    /\
   /  \
   5   2

输出:

[
  [4],
  [9,5],
  [3,0,1],
  [8,2],
  [7]
]

解题思路

深度优先搜索

对于一棵二叉树,它的垂序遍历结果是从上到下,从左到右的。 因此,我们可以以根节点为起点,利用 index 来标记每个节点的顺序,对于不同深度的节点,我们则用 depth 来标记,之后直接排序即可。

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[][]}
 */
const verticalOrder = function(root) {
    /**
     * @param {TreeNode} root
     * @param {number} index
     * @param {number} depth
     */
    const helper = (root, index, depth) => {
        if (!root) {
            return
        }
        const { val, left, right } = root
        min = Math.min(min, index)
        max = Math.max(max, index)
        if (cache.has(index)) {
            cache.get(index).push({ depth, val })
        } else {
            cache.set(index, [{ depth, val }])
        }
        helper(left, index - 1, depth + 1)
        helper(right, index + 1, depth + 1)
    }
    if (!root) {
        return []
    }
    const cache = new Map()
    const res = []
    let min = 0
    let max = 0
    helper(root, 0, 0)
    for (let i = min; i <= max; i++) {
        const nums = cache.get(i).sort((a, b) => a.depth - b.depth).map((item) => item.val)
        res.push(nums)
    }
    return res
}

广度优先搜索

前面提到的「深度优先搜索」的解法需要对数组内的元素按深度进行排序,为什么呢? 因为「深度优先搜索」是以「深度」为第一优先级的,所以可能存在同一列的值在最底层的值先被存入数组,导致结果出错。 相反,如果我们用 「广度优先搜索」 一层层的遍历,就可以保证同一列值里的顺序是没问题的。

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[][]}
 */
const verticalOrder = function(root) {
    if (!root) {
        return []
    }
    const res = []
    const cache = new Map()
    const queue = [{ root, index: 0 }]
    let min = 0
    let max = 0
    while (queue.length) {
        let loop = queue.length
        while (loop--) {
            const { root, index } = queue.shift()
            min = Math.min(min, index)
            max = Math.max(max, index)
            if (root.left) {
                queue.push({ root: root.left, index: index - 1 })
            }
            if (root.right) {
                queue.push({ root: root.right, index: index + 1 })
            }
            if (cache.has(index)) {
                cache.get(index).push(root.val)
            } else {
                cache.set(index, [root.val])
            }
        }
    }
    for (let i = min; i <= max; i++) {
        res.push(cache.get(i))
    }
    return res
}

关注我的微信公众号「tony老师的前端补习班」,即可获得最新文章~