LintCode 651: Binary Tree Vertical Order Traversal

本文探讨了二叉树的垂直遍历算法,通过不同遍历方式实现节点按列顺序输出,包括层级遍历和深度优先搜索的改进版本,确保同一列节点按从上到下、从左到右的正确顺序排列。
  1. Binary Tree Vertical Order Traversal

Given a binary tree, return the vertical order traversal of its nodes’ values. (ie, from top to bottom, column by column).

If two nodes are in the same row and column, the order should be from left to right.

Example
Example1

Inpurt: {3,9,20,#,#,15,7}
Output: [[9],[3,15],[20],[7]]
Explanation:
3
/
/
9 20
/
/
15 7
Example2

Input: {3,9,8,4,0,1,7}
Output: [[4],[9],[3,0,1],[8],[7]]
Explanation:
3
/
/
9 8
/\ /
/ /
4 01 7

解法1:按level遍历二叉树,遍历同时记录每个节点的从左往右的索引,左节点索引-1,右节点索引+1。
注意:
1)这题只能用按层次遍历,因为要保证同样索引的节点中,上面的节点排在前面。尝试了preOrder和InOrder遍历都不行。
2) 有可能右边某节点的左子节点的索引值反而排在左边某节点的右子节点的索引值前面(即相交了)。
代码如下:
这里的index就相当于解法2,3里面的pos。

/**
 * Definition of TreeNode:
 * class TreeNode {
 * public:
 *     int val;
 *     TreeNode *left, *right;
 *     TreeNode(int val) {
 *         this->val = val;
 *         this->left = this->right = NULL;
 *     }
 * }
 */


struct Node {
    TreeNode * pTreeNode;
    int index;
    Node (TreeNode *pNode = NULL, int id = 0) : pTreeNode(pNode), index(id) {}
    bool operator < (const Node & n) const {
        return index < n.index;
    }
};

class Solution {
public:
    /**
     * @param root: the root of tree
     * @return: the vertical order traversal
     */
    vector<vector<int>> verticalOrder(TreeNode * root) {
        if (!root) return {};
        vector<vector<int>> result;
        inLevelOrderTraversal(root);
        
        for (auto m : mp) {
            result.push_back(m.second);
        }  
        
        return result;
    }
private:
    map<int, vector<int>> mp; //index, values
    
    void inLevelOrderTraversal(TreeNode * root) {
        if (!root) return;
        queue<Node> q;
        q.push(Node(root, 0));
        
        while(!q.empty()) {
            Node node = q.front();
            q.pop();
            mp[node.index].push_back(node.pTreeNode->val);
            if (node.pTreeNode->left) q.push(Node(node.pTreeNode->left, node.index - 1));
            if (node.pTreeNode->right) q.push(Node(node.pTreeNode->right, node.index + 1));
        }
    }
};

下面的DFS解法不对:
如果输入是{3,9,8,4,0,1,7,#,#,#,2,5}
会输出[[4],[9,5],[3,0,1],[2,8],[7]]
而应该是
[[4],[9,5],[3,0,1],[8,2],[7]]
原因是该方法先处理左子树的节点,这样左子树的节点都在右子树的前面。而右子树的8是应该排在左子树的前面的。
要修改也可以,每个节点都必须再加一个depth,然后先比较pos,再比较depth。

class Solution {
public:
    /**
     * @param root: the root of tree
     * @return: the vertical order traversal
     */
    vector<vector<int>> verticalOrder(TreeNode *root) {
        if (!root) return vector<vector<int>>();
        map<int, vector<int>> sols;
        helper(root, 0, sols);
        vector<vector<int>> res;
        for (auto sol : sols) {
            res.push_back(sol.second);
        }
        return res;
    }
private:
    int minPos = INT_MAX, maxPos = 0;
    void helper(TreeNode *root, int pos, map<int, vector<int>> &sols) {
        if (root) {
            sols[pos].push_back(root->val);
            if (root->left) helper(root->left, pos - 1, sols);
            if (root->right) helper(root->right, pos + 1, sols);
        }
    }
}; 

下面是修正的解法:
注意:我们不能只根据先pos后depth来排序,因为不能保证pos, depth相同的时候,左边的节点在前面!所以要根据处理时候的顺序index来。
试了前中后序遍历都可以。

/**
 * Definition of TreeNode:
 * class TreeNode {
 * public:
 *     int val;
 *     TreeNode *left, *right;
 *     TreeNode(int val) {
 *         this->val = val;
 *         this->left = this->right = NULL;
 *     }
 * }
 */
struct Node {
    int val;
    int depth;
    int index;
    Node(int v, int d, int i) : val(v), depth(d), index(i) {}
    bool operator < (const Node &node) const {
        if (depth == node.depth) return index < node.index;
        return depth < node.depth;
    }
};

class Solution {
public:
    /**
     * @param root: the root of tree
     * @return: the vertical order traversal
     */
    vector<vector<int>> verticalOrder(TreeNode *root) {
        if (!root) return vector<vector<int>>();
        map<int, set<Node>> sols;
        helper(root, 0, 0, sols);
        vector<vector<int>> res;
        for (auto s : sols) {
            vector<int> tmpVec;
            for (auto node : s.second) {
                tmpVec.push_back(node.val);
            }
            res.push_back(tmpVec);
        }
        return res;
    }
private:
    int minPos = INT_MAX, maxPos = 0;
    int index = 0;
    void helper(TreeNode *root, int pos, int depth, map<int, set<Node>> &sols) {
        if (root) {
            sols[pos].insert(Node(root->val, depth, index++));
            if (root->left) helper(root->left, pos - 1, depth + 1, sols);
//            sols[pos].insert(Node(root->val, depth, index++)); 中序也可以
            if (root->right) helper(root->right, pos + 1, depth + 1, sols);
//            sols[pos].insert(Node(root->val, depth, index++)); 后序也可以
        }
    }
}; 

三刷:不用Node,直接硬处理。
map<int, set<pair<int, pair<int, int>>>> mp; //<pos, set<{depth, {index, val}>

/**
 * Definition of TreeNode:
 * class TreeNode {
 * public:
 *     int val;
 *     TreeNode *left, *right;
 *     TreeNode(int val) {
 *         this->val = val;
 *         this->left = this->right = NULL;
 *     }
 * }
 */
class Solution {
public:
    /**
     * @param root: the root of tree
     * @return: the vertical order traversal
     */
    vector<vector<int>> verticalOrder(TreeNode *root) {
        // write your code here
        int depth = 0, index = 0;
        helper(root, depth, index);
        vector<vector<int>> res;
        for (auto m : mp) {
            res.push_back(vector<int>());
            for (auto n : m.second) {
                res.back().push_back(n.second.second);
            }
        }
        return res;
    }
private:
    int index = 0;
    map<int, set<pair<int, pair<int, int>>>> mp;  //<pos, set<{depth, {index, val}>
    void helper(TreeNode *root, int depth, int pos) {
        if (!root) return;
        mp[pos].insert({depth, {index++, root->val}});
        helper(root->left, depth + 1, pos - 1);
        helper(root->right, depth + 1, pos + 1);
    }
}; 
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值