We're given a binary tree and need to return node values grouped by their vertical column. Place the tree on a grid with the root at column 0. Every left edge decreases the column by 1, and every right edge increases it by 1. Nodes that land in the same column form one group.
Within a column, nodes appear from top to bottom. If two nodes share both the same column and the same row, the one further to the left in the tree comes first. This tie-breaking rule is what makes BFS a good fit: BFS processes nodes level by level, left to right, which is the required order.
The main work is grouping nodes by column and returning the columns in left-to-right order.
0 <= number of nodes <= 100: The tree can be empty (root = null), in which case the answer is an empty list. The small size means performance does not decide between the approaches below, though the algorithmic difference matters for larger inputs.-100 <= Node.val <= 100: Values can be negative. Column indices can also be negative (any node to the left of the root), so the grouping structure must accept negative keys.Traverse the tree, assign a column index to every node, and group values by column. BFS processes nodes level by level, which gives the correct top-to-bottom ordering within each column, and within a level it visits nodes left to right, which satisfies the tie-breaking rule.
For each node, we store its value in a hash map keyed by column index. The root starts at column 0. When we visit a node at column c, its left child goes to column c - 1 and its right child to column c + 1. After the traversal, we sort the hash map keys to arrange columns from leftmost to rightmost.
column - 1.column + 1.The bottleneck is the sorting step: the traversal is O(n), and the key sort pushes the total to O(n log n). The next approach removes the sort by tracking the minimum and maximum column indices during the traversal.
This builds on Approach 1 with one change. Instead of sorting column keys after the traversal, we track the minimum and maximum column indices as we go. When the BFS finishes, we iterate from minCol to maxCol and collect each column's list, which visits the columns in left-to-right order without a sort.
The final loop reads every column from minCol to maxCol and assumes none of them is empty. This holds because each edge changes the column by exactly 1: the root-to-node path for a node at minCol passes through every column between 0 and minCol, and the same argument applies to maxCol. The occupied columns therefore form a contiguous range of integers.
The per-column order comes from the BFS queue. Parents leave the queue in left-to-right order within a level, and each parent enqueues its left child before its right child, so every level enters the queue in left-to-right order. Each column's list receives nodes top to bottom, with same-row ties resolved left to right.
minCol = 0 and maxCol = 0.minCol = min(minCol, column) and maxCol = max(maxCol, column).column - 1.column + 1.minCol to maxCol. For each column, add the corresponding list to the result.Loading animation...
Approach 2 is optimal at O(n). DFS can also solve the problem, but it needs extra bookkeeping because it does not visit nodes in level order.
DFS goes deep before going wide, so values do not arrive in top-to-bottom order within a column. A node deep in the left subtree can be recorded before a shallower node in the same column from the right subtree.
The fix is to track each node's row (depth) in addition to its column and store (row, value) pairs in each column's list. After the traversal, sorting each column's list by row restores the top-to-bottom order. The same-row tie-break comes from the traversal order: pre-order DFS finishes the entire left subtree before entering the right subtree at every branch, so two nodes with equal row and column are appended in left-to-right order, and a stable sort by row preserves that order.
(row, value) pairs.(row, node.val) to the hash map for the current column.(row + 1, column - 1) and the right child with (row + 1, column + 1).