public List<List<Integer>> verticalOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        if (root == null) return res;

        Queue<TreeNode> q = new LinkedList<TreeNode>();
        Queue<Integer> colQ = new LinkedList<Integer>();
        HashMap<Integer, List<Integer>> map = new HashMap<Integer, List<Integer>>();
        int min = 0, max = 0; // to fast reconstruct result from map

        q.add(root);
        colQ.add(0);
        while (!q.isEmpty()) { // just do BFS, no need to do level order traversal
            TreeNode node = q.remove();
            int col = colQ.remove();
            if (!map.containsKey(col)) map.put(col, new ArrayList<Integer>());
            map.get(col).add(node.val);
            if (node.left != null) {
                q.add(node.left);
                colQ.add(col - 1);
            }
            if (node.right != null) {
                q.add(node.right);
                colQ.add(col + 1);
            }
            min = Math.min(min, col);
            max = Math.max(max, col);
        }

        for (int i = min; i <= max; ++i) {
            res.add(map.get(i));
        }
        return res;
    }