Skip to content

Commit 53880cb

Browse files
authored
feat: add BFS + sorting method for lc problem 0987 (#5248)
1 parent 105153b commit 53880cb

4 files changed

Lines changed: 438 additions & 0 deletions

File tree

solution/0900-0999/0987.Vertical Order Traversal of a Binary Tree/README.md

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,4 +307,174 @@ function verticalTraversal(root: TreeNode | null): number[][] {
307307

308308
<!-- solution:end -->
309309

310+
<!-- solution:start -->
311+
312+
### 方法二:BFS + 排序
313+
314+
对于任意节点,若其坐标 $(row, col)$:
315+
316+
- 左子节点坐标 $(row + 1, col - 1)$
317+
- 右子节点坐标 $(row + 1, col + 1)$
318+
319+
因此在遍历二叉树时,需要同时记录每个节点所在的列信息。
320+
321+
于是我们能使用广度优先搜索遍历整棵二叉树。
322+
323+
题目要求最终结果按照列从左到右输出,因此得维护:
324+
325+
- `leftmostCol`:当前记录的最左列
326+
- `rightmostCol`:当前记录的最右列
327+
328+
同时使用双端队列 `columnsValues` 存储各列对应的节点值。
329+
330+
当访问到新的列时:
331+
332+
- 若列号小于 `leftmostCol`,则在双端队列左侧插入新的列容器;
333+
- 若列号大于 `rightmostCol`,则在双端队列右侧插入新的列容器。
334+
335+
对于任意列号 `col`,其在 `columnsValues` 中对应的索引为:
336+
337+
$$
338+
col - leftmostCol
339+
$$
340+
341+
因此可以在 $O(1)$ 时间内定位对应列并插入节点值。
342+
343+
完成 BFS 后,每一列中存放了属于该列的所有节点值。
344+
345+
由于 BFS 已经保证了节点按照行从上到下被访问,因此只需要对每一列内部的节点值进行升序排序,即可满足题目的要求。
346+
347+
最后依次输出所有列即可得到答案。
348+
349+
#### 复杂度分析
350+
351+
设二叉树共有 $n$ 个节点。
352+
353+
- 时间复杂度:$O(n \log n)$。
354+
355+
BFS 遍历所有节点需要 $O(n)$ 时间。各列中的节点值排序总复杂度为 $O(n \log n)$,于是有 $O(n \log n)$。
356+
357+
- 空间复杂度:$O(n)$。
358+
359+
队列、双端队列以及结果数组最多存储所有节点,因此空间复杂度为 $O(n)$。
360+
361+
<!-- tabs:start -->
362+
363+
#### Python3
364+
365+
```python
366+
# Definition for a binary tree node.
367+
# class TreeNode:
368+
# def __init__(self, val=0, left=None, right=None):
369+
# self.val = val
370+
# self.left = left
371+
# self.right = right
372+
class Solution:
373+
def verticalTraversal(self, root: Optional[TreeNode]) -> list[list[int]]:
374+
# Format: (tree node, row, column).
375+
queue: deque[tuple[TreeNode, int, int]] = deque([(root, 0, 0)])
376+
377+
# Deque append left speeds up indexing.
378+
# Each tuple format: (row, value).
379+
columns_values: deque[list[tuple[int, int]]] = deque([[]])
380+
381+
leftmost_col, rightmost_col = 0, 0
382+
383+
while queue:
384+
node, row, column = queue.popleft()
385+
386+
if column < leftmost_col:
387+
leftmost_col = column
388+
columns_values.appendleft([])
389+
390+
if column > rightmost_col:
391+
rightmost_col = column
392+
columns_values.append([])
393+
394+
columns_values[column - leftmost_col].append((row, node.val))
395+
396+
if node.left:
397+
queue.append((node.left, row + 1, column - 1))
398+
if node.right:
399+
queue.append((node.right, row + 1, column + 1))
400+
401+
vertical_traversal: list[list[int]] = []
402+
403+
for column_values in columns_values:
404+
vertical_traversal.append([])
405+
406+
column_values.sort()
407+
for _, value in column_values:
408+
vertical_traversal[-1].append(value)
409+
410+
return vertical_traversal
411+
```
412+
413+
#### C++
414+
415+
```cpp
416+
/**
417+
* Definition for a binary tree node.
418+
* struct TreeNode {
419+
* int val;
420+
* TreeNode *left;
421+
* TreeNode *right;
422+
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
423+
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
424+
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
425+
* };
426+
*/
427+
class Solution {
428+
public:
429+
vector<vector<int>> verticalTraversal(TreeNode* root) {
430+
// Each tuple format: {tree node, row, column}.
431+
deque<tuple<TreeNode*, int, int>> queue = {{root, 0, 0}};
432+
433+
// Each tuple format: {row, value}.
434+
deque<vector<tuple<int, int>>> columnsValues = {{}};
435+
436+
int leftmostCol = 0, rightmostCol = 0;
437+
438+
while (!queue.empty()) {
439+
auto [node, row, column] = queue.front();
440+
queue.pop_front();
441+
442+
if (column < leftmostCol) {
443+
leftmostCol = column;
444+
columnsValues.push_front({});
445+
}
446+
447+
if (column > rightmostCol) {
448+
rightmostCol = column;
449+
columnsValues.push_back({});
450+
}
451+
452+
columnsValues[column - leftmostCol].push_back({row, node->val});
453+
454+
if (node->left != nullptr)
455+
queue.push_back({node->left, row + 1, column - 1});
456+
457+
if (node->right != nullptr)
458+
queue.push_back({node->right, row + 1, column + 1});
459+
}
460+
461+
vector<vector<int>> verticalTraversal = {};
462+
463+
for (auto columnValues : columnsValues) { // Need to sort so no const.
464+
verticalTraversal.push_back({});
465+
466+
sort(columnValues.begin(), columnValues.end());
467+
for (const auto& [row, value] : columnValues)
468+
verticalTraversal.back().push_back(value);
469+
}
470+
471+
return verticalTraversal;
472+
}
473+
};
474+
```
475+
476+
<!-- tabs:end -->
477+
478+
<!-- solution:end -->
479+
310480
<!-- problem:end -->

solution/0900-0999/0987.Vertical Order Traversal of a Binary Tree/README_EN.md

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,4 +306,169 @@ function verticalTraversal(root: TreeNode | null): number[][] {
306306

307307
<!-- solution:end -->
308308

309+
<!-- solution:start -->
310+
311+
### Solution 2:BFS + Sorting
312+
313+
We perform a breadth-first search (BFS) on the tree.
314+
315+
Since our final answer must be returned from leftmost column to rightmost column, we maintain:
316+
- `leftmostCol`: smallest column index currently stored.
317+
- `rightmostCol`: largest column index currently stored.
318+
319+
We also use a deque `columnsValues`, where each element represents
320+
a column and stores all node values belonging to that column.
321+
322+
When a newly visited node belongs to a column outside the current range:
323+
324+
- If its column index $<$ `leftmostCol`, we put a new column container at the front of deque.
325+
- If its column index $>$ `rightmostCol`, we append a new column container to the back of deque.
326+
327+
- For any column index `col`, its corresponding position in `columnsValues` can be computed as:
328+
-
329+
$$
330+
col - `leftmostCol`
331+
$$
332+
333+
This allows us to locate target column in constant time.
334+
335+
After BFS finishes, each column contains all node values belonging to that column.
336+
337+
Since BFS already visits nodes level by level, we only need to sort values within each column
338+
in ascending order to satisfy ordering requirements of the problem.
339+
340+
Finally, we output all columns from left to right.
341+
342+
#### Complexity Analysis
343+
344+
Assume binary tree contains $n$ nodes.
345+
346+
- Time Complexity: $O(n \log n)$
347+
348+
BFS visits every node exactly once, which takes $O(n)$ time. Sorting values is $O(n \log n)$ time in worst case.
349+
Therefore, overall time complexity is $O(n \log n)$.
350+
351+
- Space Complexity: $O(n)$
352+
353+
BFS queue, deque structure, and result container may collectively store all nodes, resulting in $O(n)$ space.
354+
355+
<!-- tabs:start -->
356+
357+
#### Python3
358+
359+
```python
360+
# Definition for a binary tree node.
361+
# class TreeNode:
362+
# def __init__(self, val=0, left=None, right=None):
363+
# self.val = val
364+
# self.left = left
365+
# self.right = right
366+
class Solution:
367+
def verticalTraversal(self, root: Optional[TreeNode]) -> list[list[int]]:
368+
# Format: (tree node, row, column).
369+
queue: deque[tuple[TreeNode, int, int]] = deque([(root, 0, 0)])
370+
371+
# Deque append left speeds up indexing.
372+
# Each tuple format: (row, value).
373+
columns_values: deque[list[tuple[int, int]]] = deque([[]])
374+
375+
leftmost_col, rightmost_col = 0, 0
376+
377+
while queue:
378+
node, row, column = queue.popleft()
379+
380+
if column < leftmost_col:
381+
leftmost_col = column
382+
columns_values.appendleft([])
383+
384+
if column > rightmost_col:
385+
rightmost_col = column
386+
columns_values.append([])
387+
388+
columns_values[column - leftmost_col].append((row, node.val))
389+
390+
if node.left:
391+
queue.append((node.left, row + 1, column - 1))
392+
if node.right:
393+
queue.append((node.right, row + 1, column + 1))
394+
395+
vertical_traversal: list[list[int]] = []
396+
397+
for column_values in columns_values:
398+
vertical_traversal.append([])
399+
400+
column_values.sort()
401+
for _, value in column_values:
402+
vertical_traversal[-1].append(value)
403+
404+
return vertical_traversal
405+
```
406+
407+
#### C++
408+
409+
```cpp
410+
/**
411+
* Definition for a binary tree node.
412+
* struct TreeNode {
413+
* int val;
414+
* TreeNode *left;
415+
* TreeNode *right;
416+
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
417+
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
418+
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
419+
* };
420+
*/
421+
class Solution {
422+
public:
423+
vector<vector<int>> verticalTraversal(TreeNode* root) {
424+
// Each tuple format: {tree node, row, column}.
425+
deque<tuple<TreeNode*, int, int>> queue = {{root, 0, 0}};
426+
427+
// Each tuple format: {row, value}.
428+
deque<vector<tuple<int, int>>> columnsValues = {{}};
429+
430+
int leftmostCol = 0, rightmostCol = 0;
431+
432+
while (!queue.empty()) {
433+
auto [node, row, column] = queue.front();
434+
queue.pop_front();
435+
436+
if (column < leftmostCol) {
437+
leftmostCol = column;
438+
columnsValues.push_front({});
439+
}
440+
441+
if (column > rightmostCol) {
442+
rightmostCol = column;
443+
columnsValues.push_back({});
444+
}
445+
446+
columnsValues[column - leftmostCol].push_back({row, node->val});
447+
448+
if (node->left != nullptr)
449+
queue.push_back({node->left, row + 1, column - 1});
450+
451+
if (node->right != nullptr)
452+
queue.push_back({node->right, row + 1, column + 1});
453+
}
454+
455+
vector<vector<int>> verticalTraversal = {};
456+
457+
for (auto columnValues : columnsValues) { // Need to sort so no const.
458+
verticalTraversal.push_back({});
459+
460+
sort(columnValues.begin(), columnValues.end());
461+
for (const auto& [row, value] : columnValues)
462+
verticalTraversal.back().push_back(value);
463+
}
464+
465+
return verticalTraversal;
466+
}
467+
};
468+
```
469+
470+
<!-- tabs:end -->
471+
472+
<!-- solution:end -->
473+
309474
<!-- problem:end -->

0 commit comments

Comments
 (0)