Link to LeetCode Problem

S1: DFS 记录坐标+排序

把二叉树放到坐标网格上看看,以根节点为原点,往左的节点 x--,往右的节点 x++,往下的节点 y--

https://camo.githubusercontent.com/36c0d85d07b7b9028cf20c19b87e242ea0e37216e9453e4bb5cfe0c965e48b1b/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f7375756b69692f39312d646179732d616c676f726974686d2f6173736574732f3938375f302e706e67

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> verticalTraversal(TreeNode* root) {
        vector<tuple<int, int, int>> nodes;

        function<void(TreeNode* root, int x, int y)> dfs = [&](TreeNode* root, int x, int y) {
            if (root == nullptr) return;
            nodes.emplace_back(x, y, root->val);
            dfs(root->left, x - 1, y + 1);
            dfs(root->right, x + 1, y + 1);
        };

        dfs(root, 0, 0);
        sort(nodes.begin(), nodes.end());
        vector<vector<int>> ans;
        int curX = INT_MIN;
        for (const auto& [x, y, val] : nodes) {
            if (x > curX) {
                curX = x;
                ans.emplace_back();
            }
            ans.back().push_back(val);
        }
        return ans;
    }
};
/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[][]}
 */
var verticalTraversal = function (root) {
    if (!root) return [];

    // 坐标集合以 x 坐标分组
    const pos = {};
    // dfs 遍历节点并记录每个节点的坐标
    dfs(root, 0, 0);

    // 得到所有节点坐标后,先按 x 坐标升序排序
    let sorted = Object.keys(pos)
        .sort((a, b) => +a - +b)
        .map(key => pos[key]);

    // 再给 x 坐标相同的每组节点坐标分别排序
    sorted = sorted.map(g => {
        g.sort((a, b) => {
            // y 坐标相同的,按节点值升序排
            if (a[0] === b[0]) return a[1] - b[1];
            // 否则,按 y 坐标降序排
            else return b[0] - a[0];
        });
        // 把 y 坐标去掉,返回节点值
        return g.map(el => el[1]);
    });

    return sorted;

    // *********************************
    function dfs(root, x, y) {
        if (!root) return;

        x in pos || (pos[x] = []);
        // 保存坐标数据,格式是: [y, val]
        pos[x].push([y, root.val]);

        dfs(root.left, x - 1, y - 1);
        dfs(root.right, x + 1, y - 1);
    }
};

S2: BFS 记录坐标+排序

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[][]}
 */
var verticalTraversal = function (root) {
    if (!root) return [];

    // 坐标集合以 x 坐标分组
    const pos = bfs(root);

    // 得到所有节点坐标后,先按 x 坐标升序排序
    let sorted = Object.keys(pos)
        .sort((a, b) => +a - +b)
        .map(key => pos[key]);

    // 再给 x 坐标相同的每组节点坐标分别排序
    sorted = sorted.map(g => {
        g.sort((a, b) => {
            // y 坐标相同的,按节点值升序排
            if (a[0] === b[0]) return a[1] - b[1];
            // 否则,按 y 坐标降序排
            else return b[0] - a[0];
        });
        // 把 y 坐标去掉,返回节点值
        return g.map(el => el[1]);
    });

    return sorted;

    // *********************************
    function bfs(root) {
        // 队列中数据格式是: [x, y, val]
        const queue = [[0, 0, root]];
        const pos = {};
        while (queue.length) {
            let size = queue.length;

            while (size--) {
                const [x, y, node] = queue.shift();
                x in pos || (pos[x] = []);
                // 保存坐标数据到 pos,格式是: [y, val]
                pos[x].push([y, node.val]);
                node.left && queue.push([x - 1, y - 1, node.left]);
                node.right && queue.push([x + 1, y - 1, node.right]);
            }
        }
        return pos;
    }
};