DEV Community

Cover image for Solution: Vertical Order Traversal of a Binary Tree
seanpgallivan
seanpgallivan

Posted on

Solution: Vertical Order Traversal of a Binary Tree

This is part of a series of Leetcode solution explanations (index). If you liked this solution or found it useful, please like this post and/or upvote my solution post on Leetcode's forums.


Leetcode Problem #987 (Hard): Vertical Order Traversal of a Binary Tree


Description:

Given the root of a binary tree, calculate the vertical order traversal of the binary tree.

For each node at position (row, col), its left and right children will be at positions (row + 1, col - 1) and (row + 1, col + 1) respectively. The root of the tree is at (0, 0).

The vertical order traversal of a binary tree is a list of top-to-bottom orderings for each column index starting from the leftmost column and ending on the rightmost column. There may be multiple nodes in the same row and same column. In such a case, sort these nodes by their values.

Return the vertical order traversal of the binary tree.


Examples:

Example 1:
Input: root = [3,9,20,null,null,15,7]
Output: [[9],[3,15],[20],[7]]
Explanation: Column -1: Only node 9 is in this column.
Column 0: Nodes 3 and 15 are in this column in that order from top to bottom.
Column 1: Only node 20 is in this column.
Column 2: Only node 7 is in this column.
Visual: Example 1 Visual
Example 2:
Input: root = [1,2,3,4,5,6,7]
Output: [[4],[2],[1,5,6],[3],[7]]
Explanation: Column -2: Only node 4 is in this column.
Column -1: Only node 2 is in this column.
Column 0: Nodes 1, 5, and 6 are in this column. 1 is at the top, so it comes first. 5 and 6 are at the same position (2, 0), so we order them by their value, 5 before 6.
Column 1: Only node 3 is in this column.
Column 2: Only node 7 is in this column.
Visual: Example 2 Visual
Example 3:
Input: root = [1,2,3,4,6,5,7]
Output: [[4],[2],[1,5,6],[3],[7]]
Explanation: This case is the exact same as example 2, but with nodes 5 and 6 swapped.
Note that the solution remains the same since 5 and 6 are in the same location and should be ordered by their values.
Visual: Example 3 Visual

Constraints:

  • The number of nodes in the tree is in the range [1, 1000].
  • 0 <= Node.val <= 1000

Idea:

The instructions for this problem are basically asking us to return the tree's contents sorted first by node x-value, then by node y-value, then by node value. Since the range of x-values is -999 to 999 (11 bits), the range of y-values is 0 to 999 (10 bits), and the range of node values is 1 to 1000 (10 bits), the idea becomes: why not combine all three values into one integer to make sorting exceedingly easy?

At that point, we can simply use any method (I chose recursion) to traverse the entire tree while encoding the three data into one integer via bitwise shifts before grouping it all together to sort. Then any method of sorting will suffice to place them in the correct order.

Finally, we just need to group the results into subarrays by x-value, remembering to convert the integer back to just the node value using a bitwise AND bitmask. I chose to use a 2-pointer system to identify the subarray group and then used slice and map.

This code is fairly agnostic, but I've included examples for both Python and Javascript. Python doesn't have a splice function, however, so I couldn't modify the initial array in-place.


Python Code:

class Solution(object):
    def verticalTraversal(self, root):
        res, ans = [], []
        def rc(node, x, y):
            res.append((x << 20) + (y << 10) + node.val)
            if node.left: rc(node.left, x-1, y+1)
            if node.right: rc(node.right, x+1, y+1)
        rc(root, 1000, 0)
        res.sort()
        l, r, rlen = 0, 0, len(res)
        while r < rlen:
            curr = res[l] >> 20
            while r < rlen and res[r] >> 20 == curr: r += 1
            group = map(lambda x: x & (1 << 10) - 1, res[l:r])
            ans.append(group)
            l = r
        return ans
Enter fullscreen mode Exit fullscreen mode

Javascript Code:

var verticalTraversal = function(root) {
    let ans = []
    const rc = (node, x, y) => {
        ans.push((x << 20) + (y << 10) + node.val)
        if (node.left) rc(node.left, x-1, y+1)
        if (node.right) rc(node.right, x+1, y+1)
    }
    rc(root, 1000, 0)
    ans.sort((a,b) => a - b)
    for (let l = r = 0; r < ans.length; r = ++l) {
        let curr = ans[l] >> 20
        while (ans[r] >> 20 == curr) r++
        let group = ans.slice(l,r).map(el => el & (1 << 10) - 1)
        ans.splice(l, r-l, group)
    }
    return ans
};
Enter fullscreen mode Exit fullscreen mode

Top comments (0)