The O(n) Club: Vertical Order Traversal of a Binary Tree: Columns, Chaos, and Why BFS Wins

The O(n) Club: Vertical Order Traversal of a Binary Tree — Columns, Chaos, and Why BFS Wins

⚡ TL;DR

Want to print a binary tree column by column (left to right, top to bottom within columns)? Ignore DFS daydreams—BFS plus a Map is your BFF. Here’s the gossipy Java skeleton:

// BFS vertical order quickie
Queue<Pair<TreeNode, Integer>> queue = new LinkedList<>();
Map<Integer, List<Integer>> colTable = new HashMap<>();
queue.offer(new Pair(root, 0));
while (!queue.isEmpty()) {
    Pair<TreeNode, Integer> entry = queue.poll();
    // add entry.getKey().val to colTable.get(entry.getValue())
    // add kids with col-1, col+1
}

🧠 How Devs Usually Mess This Up

Confession: Most devs try DFS and then spend an afternoon playing whack-a-bug with the ordering rules. DFS explores all the wrong places at the wrong times, so your verticals come out organized like my desk (read: not at all). People also blunder by:

  • Forgetting columns can be negative, aka, the left wing of your tree doesn’t vanish into the upside down.
  • Ignoring that nodes at the same spot (column & row) may need order-by-value magic.
  • Confusing different specs—sometimes it’s BFS order, sometimes value-order per column. Interviewers love variety, right?

🔍 What’s Actually Going On

Your binary tree’s a mini Manhattan. The root stands at column 0, row 0, owning Central Park. Go left? That’s column-1, one row down. Go right? You guessed it: column+1. Nodes stack in columns; rows (a.k.a. distance from the root) sort top-to-bottom. If you want vertical order that doesn’t look like alphabet soup, BFS walks floor-by-floor, so nodes at the same level get listed in glorious left-to-right order. Use a Map: column index → list of values. Blend with BFS for level order, and you’ve got skyline architecture worthy of LeetCode Zillow.

🛠️ PseudoCode

  • Create a HashMap: key = column, value = list of values at that column
  • Slap the root into a BFS queue with column 0
  • Track minCol and maxCol as you go (trust me, you’ll need them for output range)
  • BFS loop: for each node, drop its value into the column’s list, add left child with col-1, right child with col+1. Tweak min/max col champs.
  • After the loop, walk from minCol to maxCol; that’s your output
// Java pseudo-for-humans
Map<Integer, List<Integer>> columns = new HashMap<>();
Queue<Pair<TreeNode, Integer>> queue = new LinkedList<>();
int min = 0, max = 0;
queue.offer(new Pair(root, 0));
while (!queue.isEmpty()) {
    var p = queue.poll();
    TreeNode node = p.getKey();
    int col = p.getValue();
    columns.computeIfAbsent(col, k -> new ArrayList<>()).add(node.val);
    min = Math.min(min, col); max = Math.max(max, col);
    if(node.left != null) queue.offer(new Pair(node.left, col-1));
    if(node.right != null) queue.offer(new Pair(node.right, col+1));
}
for(int i = min; i <= max; i++) output.add(columns.get(i));

💻 The Code

// Full Java solution
class Solution {
    public List<List<Integer>> verticalOrder(TreeNode root) {
        List<List<Integer>> result = new ArrayList<>();
        if (root == null) return result;
        Map<Integer, List<Integer>> colMap = new HashMap<>();
        Queue<Pair<TreeNode, Integer>> queue = new LinkedList<>();
        queue.offer(new Pair(root, 0));
        int min = 0, max = 0;
        while (!queue.isEmpty()) {
            Pair<TreeNode, Integer> p = queue.poll();
            TreeNode node = p.getKey();
            int col = p.getValue();
            colMap.computeIfAbsent(col, k -> new ArrayList<>()).add(node.val);
            min = Math.min(min, col);
            max = Math.max(max, col);
            if (node.left != null) queue.offer(new Pair(node.left, col-1));
            if (node.right != null) queue.offer(new Pair(node.right, col+1));
        }
        for (int i = min; i <= max; i++) {
            result.add(colMap.get(i));
        }
        return result;
    }
}
// Use javafx.util.Pair or roll your own simple Pair class

⚠️ Pitfalls, Traps & Runtime Smacks

  • Overlapping nodes (same column, same row): Some specs say to sort by value—so if that comes up, group (row, value) pairs then sort by row then by value.
  • Off-by-one column handling: Your far-left column might be -17. Don’t start at 0 by default.
  • DFS trickery: DFS is faster to type, slower to debug in this case.
  • Complexity: O(n) overall if you trust your map, plus a smidge for final sorting if column values overlap.

🧠 Interviewer Brain-Tattoo

“If you treat DFS like duct-tape, expect leaks. For columnar order, BFS is the city planner; DFS is the guy drawing random doodles on the blueprint.”

Previous Article

The O(n) Club: Unique Paths III and the Roomba That Never Misses a Spot

Next Article

The O(n) Club: Candy: Because Satisfying Kids—and Your Interviewer—Takes Two Passes