|
| 1 | +--- |
| 2 | +title: 987.二叉树的垂序遍历 |
| 3 | +date: 2024-02-13 11:03:40 |
| 4 | +tags: [题解, LeetCode, 困难, 树, 深度优先搜索, 广度优先搜索, BFS, 哈希表, 二叉树] |
| 5 | +--- |
| 6 | + |
| 7 | +# 【LetMeFly】987.二叉树的垂序遍历:遍历时存节点信息,遍历完自定义排序 |
| 8 | + |
| 9 | +力扣题目链接:[https://leetcode.cn/problems/vertical-order-traversal-of-a-binary-tree/](https://leetcode.cn/problems/vertical-order-traversal-of-a-binary-tree/) |
| 10 | + |
| 11 | +<p>给你二叉树的根结点 <code>root</code> ,请你设计算法计算二叉树的<em> </em><strong>垂序遍历</strong> 序列。</p> |
| 12 | + |
| 13 | +<p>对位于 <code>(row, col)</code> 的每个结点而言,其左右子结点分别位于 <code>(row + 1, col - 1)</code> 和 <code>(row + 1, col + 1)</code> 。树的根结点位于 <code>(0, 0)</code> 。</p> |
| 14 | + |
| 15 | +<p>二叉树的 <strong>垂序遍历</strong> 从最左边的列开始直到最右边的列结束,按列索引每一列上的所有结点,形成一个按出现位置从上到下排序的有序列表。如果同行同列上有多个结点,则按结点的值从小到大进行排序。</p> |
| 16 | + |
| 17 | +<p>返回二叉树的 <strong>垂序遍历</strong> 序列。</p> |
| 18 | + |
| 19 | +<p> </p> |
| 20 | + |
| 21 | +<p><strong>示例 1:</strong></p> |
| 22 | +<img alt="" src="https://assets.leetcode.com/uploads/2021/01/29/vtree1.jpg" style="width: 431px; height: 304px;" /> |
| 23 | +<pre> |
| 24 | +<strong>输入:</strong>root = [3,9,20,null,null,15,7] |
| 25 | +<strong>输出:</strong>[[9],[3,15],[20],[7]] |
| 26 | +<strong>解释:</strong> |
| 27 | +列 -1 :只有结点 9 在此列中。 |
| 28 | +列 0 :只有结点 3 和 15 在此列中,按从上到下顺序。 |
| 29 | +列 1 :只有结点 20 在此列中。 |
| 30 | +列 2 :只有结点 7 在此列中。</pre> |
| 31 | + |
| 32 | +<p><strong>示例 2:</strong></p> |
| 33 | +<img alt="" src="https://assets.leetcode.com/uploads/2021/01/29/vtree2.jpg" style="width: 512px; height: 304px;" /> |
| 34 | +<pre> |
| 35 | +<strong>输入:</strong>root = [1,2,3,4,5,6,7] |
| 36 | +<strong>输出:</strong>[[4],[2],[1,5,6],[3],[7]] |
| 37 | +<strong>解释:</strong> |
| 38 | +列 -2 :只有结点 4 在此列中。 |
| 39 | +列 -1 :只有结点 2 在此列中。 |
| 40 | +列 0 :结点 1 、5 和 6 都在此列中。 |
| 41 | + 1 在上面,所以它出现在前面。 |
| 42 | + 5 和 6 位置都是 (2, 0) ,所以按值从小到大排序,5 在 6 的前面。 |
| 43 | +列 1 :只有结点 3 在此列中。 |
| 44 | +列 2 :只有结点 7 在此列中。 |
| 45 | +</pre> |
| 46 | + |
| 47 | +<p><strong>示例 3:</strong></p> |
| 48 | +<img alt="" src="https://assets.leetcode.com/uploads/2021/01/29/vtree3.jpg" style="width: 512px; height: 304px;" /> |
| 49 | +<pre> |
| 50 | +<strong>输入:</strong>root = [1,2,3,4,6,5,7] |
| 51 | +<strong>输出:</strong>[[4],[2],[1,5,6],[3],[7]] |
| 52 | +<strong>解释:</strong> |
| 53 | +这个示例实际上与示例 2 完全相同,只是结点 5 和 6 在树中的位置发生了交换。 |
| 54 | +因为 5 和 6 的位置仍然相同,所以答案保持不变,仍然按值从小到大排序。</pre> |
| 55 | + |
| 56 | +<p> </p> |
| 57 | + |
| 58 | +<p><strong>提示:</strong></p> |
| 59 | + |
| 60 | +<ul> |
| 61 | + <li>树中结点数目总数在范围 <code>[1, 1000]</code> 内</li> |
| 62 | + <li><code>0 <= Node.val <= 1000</code></li> |
| 63 | +</ul> |
| 64 | + |
| 65 | + |
| 66 | + |
| 67 | +## 方法一:遍历时存节点信息,遍历完自定义排序(以广度优先搜索为例) |
| 68 | + |
| 69 | +[广度优先搜索(BFS)](https://leetcode.letmefly.xyz/tags/BFS/)相信大家都不陌生,因此我们可以二话不说将二叉树广搜一遍,在搜索过程中将所需要的信息计算并存下来,剩下的就是按照题目规则自定义排序了。 |
| 70 | + |
| 71 | +都需要哪些信息呢?需要“节点在哪一列”、“节点深度”、“节点值”。 |
| 72 | + |
| 73 | +遍历过程中将上述三元组存下来,遍历完成后依据这三个信息排序,作为答案并返回即可。 |
| 74 | + |
| 75 | ++ 时间复杂度$O(N\log N)$,其中$N$是二叉树中节点的个数 |
| 76 | ++ 空间复杂度$O(N)$ |
| 77 | + |
| 78 | +### AC代码 |
| 79 | + |
| 80 | +#### C++ |
| 81 | + |
| 82 | +```cpp |
| 83 | +class Solution { |
| 84 | +public: |
| 85 | + vector<vector<int>> verticalTraversal(TreeNode* root) { |
| 86 | + queue<NodeInfo> q; // [<node, <col, height>>, ... |
| 87 | + q.push({root, {0, 1}}); |
| 88 | + vector<NodeInfo> v; |
| 89 | + while (q.size()) { |
| 90 | + NodeInfo thisNode = q.front(); |
| 91 | + q.pop(); |
| 92 | + v.push_back(thisNode); |
| 93 | + if (thisNode.first->left) { |
| 94 | + q.push({thisNode.first->left, {thisNode.second.first - 1, thisNode.second.second + 1}}); |
| 95 | + } |
| 96 | + if (thisNode.first->right) { |
| 97 | + q.push({thisNode.first->right, {thisNode.second.first + 1, thisNode.second.second + 1}}); |
| 98 | + } |
| 99 | + } |
| 100 | + sort(v.begin(), v.end(), [&](const NodeInfo& a, const NodeInfo& b) { |
| 101 | + return a.second == b.second ? a.first->val < b.first->val : a.second < b.second; |
| 102 | + }); |
| 103 | + vector<vector<int>> ans; |
| 104 | + int lastCol = 1000000; |
| 105 | + for (NodeInfo& a : v) { |
| 106 | + if (a.second.first != lastCol) { |
| 107 | + lastCol = a.second.first; |
| 108 | + ans.push_back({}); |
| 109 | + } |
| 110 | + ans.back().push_back(a.first->val); |
| 111 | + } |
| 112 | + return ans; |
| 113 | + } |
| 114 | +}; |
| 115 | +``` |
| 116 | +
|
| 117 | +#### Python |
| 118 | +
|
| 119 | +```python |
| 120 | +# from typing import List |
| 121 | +
|
| 122 | +# # Definition for a binary tree node. |
| 123 | +# class TreeNode: |
| 124 | +# def __init__(self, val=0, left=None, right=None): |
| 125 | +# self.val = val |
| 126 | +# self.left = left |
| 127 | +# self.right = right |
| 128 | +
|
| 129 | +class Solution: |
| 130 | + def verticalTraversal(self, root: TreeNode) -> List[List[int]]: |
| 131 | + q = [(0, 0, root)] # [(col, depth, node), ... |
| 132 | + v = [] # [(col, depth, val), ...] |
| 133 | + while q: |
| 134 | + thisCol, thisDepth, thisNode = q.pop() # actually is't queue but a stack |
| 135 | + v.append((thisCol, thisDepth, thisNode.val)) |
| 136 | + if thisNode.left: |
| 137 | + q.append((thisCol - 1, thisDepth + 1, thisNode.left)) |
| 138 | + if thisNode.right: |
| 139 | + q.append((thisCol + 1, thisDepth + 1, thisNode.right)) |
| 140 | + v.sort() |
| 141 | + ans = [] |
| 142 | + lastCol = 100000 |
| 143 | + for col, _, val in v: |
| 144 | + if col != lastCol: |
| 145 | + lastCol = col |
| 146 | + ans.append([]) |
| 147 | + ans[-1].append(val) |
| 148 | + return ans |
| 149 | +
|
| 150 | +``` |
| 151 | + |
| 152 | +> 同步发文于CSDN,原创不易,转载经作者同意后请附上[原文链接](https://blog.tisfy.eu.org/2024/02/13/LeetCode%200987.%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E5%9E%82%E5%BA%8F%E9%81%8D%E5%8E%86/)哦~ |
| 153 | +> Tisfy:[https://letmefly.blog.csdn.net/article/details/136106019](https://letmefly.blog.csdn.net/article/details/136106019) |
0 commit comments