Solution

class Solution {
    class Pair {
        TreeNode node;
        int hd;
        int level;
        
        public Pair(TreeNode node, int hd, int level) {
            this.node = node;
            this.hd = hd;
            this.level = level;
        }
    }
 
    public List<List<Integer>> verticalTraversal(TreeNode root) {
        if (root == null) return new ArrayList<>();
 
        List<List<Integer>> result = new ArrayList<>();
        
        // TreeMap to store the nodes at each horizontal distance (Visualised Below!)
        TreeMap<Integer, TreeMap<Integer, PriorityQueue<Integer>>> map = new TreeMap<>();
        
        // Queue to perform level-order traversal
        Queue<Pair> queue = new LinkedList<>();
        
        // Start with the root node at horizontal distance 0 and level 0
        queue.add(new Pair(root, 0, 0));
        
        while (!queue.isEmpty()) {
            Pair temp = queue.poll();
            TreeNode node = temp.node;
            int hd = temp.hd;
            int level = temp.level;
            
            // If the horizontal distance is not present in the map, add it
            if (!map.containsKey(hd)) {
                map.put(hd, new TreeMap<>());
            }
            // If the level is not present at this horizontal distance, add it
            if (!map.get(hd).containsKey(level)) {
                map.get(hd).put(level, new PriorityQueue<>());
            }
            // Add the current node to the priority queue for its horizontal distance and level
            map.get(hd).get(level).add(node.val);
            
            // Enqueue left child with horizontal distance hd - 1 and level + 1
            if (node.left != null) {
                queue.add(new Pair(node.left, hd - 1, level + 1));
            }
            
            // Enqueue right child with horizontal distance hd + 1 and level + 1
            if (node.right != null) {
                queue.add(new Pair(node.right, hd + 1, level + 1));
            }
        }
        
 
        for (TreeMap<Integer, PriorityQueue<Integer>> levels : map.values()) {
            List<Integer> vertical = new ArrayList<>();
            for (PriorityQueue<Integer> nodes : levels.values()) {
                while (!nodes.isEmpty()) {
                    vertical.add(nodes.poll());
                }
            }
            result.add(vertical);
        }
 
        return result;
    
    }
}

Visualization of data structure to store the values:

 
TreeMap<Integer, 
		TreeMap<Integer, 
				PriorityQueue<Integer>>> 
		map = new TreeMap<>();
 
map = {
    -2: {
        2: [4]
    },
    -1: {
        1: [2]
    },
    0: {
        0: [1],
        2: [5, 6]
    },
    1: {
        1: [3]
    },
    2: {
        2: [7]
    }
}