Vertical Order Traversal of a Binary Tree

LeetCode August - Day 7

Problem Statement

Given a binary tree, return the vertical order traversal of its nodes values.

For each node at position (X, Y), its left and right children respectively will be at positions (X-1, Y-1) and (X+1, Y-1).

Running a vertical line from X = -infinity to X = +infinity, whenever the vertical line touches some nodes, we report the values of the nodes in order from top to bottom (decreasing Y coordinates).

If two nodes have the same position, then the value of the node that is reported first is the value that is smaller.

Return an list of non-empty reports in order of X coordinate. Every report will have a list of values of nodes.

Example 1:

Image taken from LeetCode

Input: [3,9,20,null,null,15,7]
Output: [[9],[3,15],[20],[7]]

Explanation:
Without loss of generality, we can assume the root node is at position (0, 0):
Then, the node with value 9 occurs at position (-1, -1);
The nodes with values 3 and 15 occur at positions (0, 0) and (0, -2);
The node with value 20 occurs at position (1, -1);
The node with value 7 occurs at position (2, -2).

Example 2:

Image take from LeetCode

Input: [1,2,3,4,5,6,7]
Output: [[4],[2],[1,5,6],[3],[7]]

Explanation:
The node with value 5 and the node with value 6 have the same position according to the given scheme.
However, in the report “[1,5,6]”, the node value of 5 comes first since 5 is smaller than 6.

Note:

The tree will have between 1 and 1000 nodes.
Each node’s value will be between 0 and 1000.

Inputs, Outputs, Constraints & Exceptions

  • I: TreeNode(val,left,right) {root}
  • O: number[]
  • C: none/optimise
  • E: - root is null
    • root is only node
    • all nodes are only along one branch

Code

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[][]}
 */
function verticalTraversal(root) {
  if(root === null) {
    return []
  }

  const cache = new Map(); // col -> [row, val] 
  let maxC = 0, minC = 0;

  const dfs = (node, row, col) => {
    minC = Math.min(col, minC)
    maxC = Math.max(col, maxC)

    let colNodes = cache.get(col)
    if(colNodes){
      cache.set(col, [...colNodes, [row, node.val]])
    } else {
      cache.set(col, [[row, node.val]])
    }

    if(node.left){
      dfs(node.left, row + 1, col - 1)
    }

    if(node.right){
      dfs(node.right, row + 1, col + 1)
    }
  }

  dfs(root, 0, 0)

  const result = []
  for(let i = minC; i < maxC + 1; i++){
    let colNodes = cache.get(i)
      .sort((a,b) => {
        if(a[0] === b[0]) return a[1] - b[1];
        else return a[0] - b[0]
      })
      .map( curr => {
        return curr[1]
      })
    result.push(colNodes)
  }
  
  return result;
};

Time complexity: O(n log n)
Space complexity: O(n)