[LeetCode] 987. Vertical Order Traversal of a Binary Tree 竖直遍历二叉树


Given the root of a binary tree, calculate the vertical order traversal of the binary tree.

For each node at position (row, col), its left and right children will be at positions (row + 1, col - 1) and (row + 1, col + 1) respectively. The root of the tree is at (0, 0).

The vertical order traversal of a binary tree is a list of top-to-bottom orderings for each column index starting from the leftmost column and ending on the rightmost column. There may be multiple nodes in the same row and same column. In such a case, sort these nodes by their values.

Return the vertical order traversal of the binary tree.

Example 1:

Input: root = [3,9,20,null,null,15,7]
Output: [[9],[3,15],[20],[7]]
Explanation:
Column -1: Only node 9 is in this column.
Column 0: Nodes 3 and 15 are in this column in that order from top to bottom.
Column 1: Only node 20 is in this column.
Column 2: Only node 7 is in this column.

Example 2:

Input: root = [1,2,3,4,5,6,7]
Output: [[4],[2],[1,5,6],[3],[7]]
Explanation:
Column -2: Only node 4 is in this column.
Column -1: Only node 2 is in this column.
Column 0: Nodes 1, 5, and 6 are in this column.
          1 is at the top, so it comes first.
          5 and 6 are at the same position (2, 0), so we order them by their value, 5 before 6.
Column 1: Only node 3 is in this column.
Column 2: Only node 7 is in this column.

Example 3:

Input: root = [1,2,3,4,6,5,7]
Output: [[4],[2],[1,5,6],[3],[7]]
Explanation:
This case is the exact same as example 2, but with nodes 5 and 6 swapped.
Note that the solution remains the same since 5 and 6 are in the same location and should be ordered by their values.

Constraints:

  • The number of nodes in the tree is in the range [1, 1000].
  • 0 <= Node.val <= 1000

这道题是让给二叉树进行竖直遍历,怎么隐约感觉以前做过这道题,结果去查了一下,果然有 Binary Tree Vertical Order Traversal。怎么把标题顺序调换一下就是一道新题,Excuse me???结果仔细研究一下,两道题还真有些不同,不同点就是在于这道题对于同一列中的结点值的顺序还有要求,此处应有尼克杨问号脸??就是说默认是按y值从大到小排列的,但如果y值相同,则按结点值从小到大排,我也是给跪了。好吧,你赢了,将就着做吧。这道题之所以比之前的那道类似的题目难,原因是把y值也扯进来了,那么数据结构中也要给y值留个位置,大体思路其实还是一样的。这里要用到比较复杂的数据结构,同时用到两个 TreeMap 嵌在一块。用 TreeMap 的好处就是可以自动排序了,外层的映射 key 是x值,这样保证了x值是从小到大的,符合题目中要求的顺序。内层的映射是y值和一个放结点值的 TreeSet,之所以使用 TreeSet 也是利用其可以自动排序的特点,因为当y值相同时,需要结点值从小到大排列(但是后来 LeetCode 加了新的 test case [3,1,4,0,2,2],使得同一个y值时可能有相同的结点值,这样就不能用 TreeSet 了,因为其会自动去重复,这里还是用 vector)。同理,在队列 queue 中也要把y值包含进去,这里可以用一个 pair 对儿,分别是结点和坐标值,初始时把根结点,还有其坐标放入队列开始遍历吧。遍历的过程其实并不难,就是取出队首结点,取出坐标,更新 TreeMap 中的映射,然后将存在的左右子结点加入队列中继续遍历。这里细心的读者会发现,为啥左右子结点的坐标的y值都是加1,而题目中明明写的减1啊?这是因为 TreeMap 是从小到大的默认顺序,而题目中要求的y值是从上到下递减,这样就是从大到小的顺序了,为了方便起见,改成加1,就可以得到题目中要求的顺序了,算是个小 trick 吧。当遍历结束后,所有的数据都存在了 TreeMap 中,只要遍历 TreeMap,并按顺序取出每列的结点值(这里由于之前改为了 vector,所以需要再排个序),组成数组放入结果 res 中即可,参见代码如下:


解法一:

class Solution {
public:
    vector<vector<int>> verticalTraversal(TreeNode* root) {
        vector<vector<int>> res;
        map<int, map<int, vector<int>>> m;
        queue<pair<TreeNode*, vector<int>>> q;
        q.push({root, {0, 0}});
        while (!q.empty()) {
            auto t = q.front(); q.pop();
            TreeNode *node = t.first;
            int x = t.second[0], y = t.second[1];
            m[x][y].push_back(node->val);
            if (node->left) q.push({node->left, {x - 1, y + 1}});
            if (node->right) q.push({node->right, {x + 1, y + 1}});
        }
        for (auto &a : m) {
            vector<int> col;
            for (auto &it : a.second) {
                sort(it.second.begin(), it.second.end());
                col.insert(col.end(), it.second.begin(), it.second.end());
            }
            res.push_back(col);
        }
        return res;
    }
};

接下来是递归的写法,基本解题思路没有太大的区别,可以参见上面的讲解来理解,参见代码如下:


解法二:

class Solution {
public:
    vector<vector<int>> verticalTraversal(TreeNode* root) {
        vector<vector<int>> res;
        map<int, map<int, vector<int>>> m;
        helper(root, 0, 0, m);
        for (auto &a : m) {
            vector<int> col;
            for (auto &it : a.second) {
                sort(it.second.begin(), it.second.end());
                col.insert(col.end(), it.second.begin(), it.second.end());
            }
            res.push_back(col);
        }
        return res;
    }
    void helper(TreeNode* root, int x, int y, map<int, map<int, vector<int>>>& m) {
        if (!root) return;
        m[x][y].push_back(root->val);
        helper(root->left, x - 1, y + 1, m);
        helper(root->right, x + 1, y + 1, m);
    }
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/987


类似题目:

Binary Tree Vertical Order Traversal


参考资料:

https://leetcode.com/problems/vertical-order-traversal-of-a-binary-tree/

https://leetcode.com/problems/vertical-order-traversal-of-a-binary-tree/discuss/260502/C%2B%2B-BFSDFS

https://leetcode.com/problems/vertical-order-traversal-of-a-binary-tree/discuss/231140/Add-clarification-for-the-output-order

https://leetcode.com/problems/vertical-order-traversal-of-a-binary-tree/discuss/231125/Java-HashMap-and-TreeMap-and-PriorityQueue-Solution


LeetCode All in One 题目讲解汇总(持续更新中...)

posted @ 2020-12-11 15:38  Grandyang  阅读(1651)  评论(3编辑  收藏  举报
Fork me on GitHub