forked from keon/algorithms
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbinary_tree_views.py
More file actions
156 lines (127 loc) · 4.6 KB
/
binary_tree_views.py
File metadata and controls
156 lines (127 loc) · 4.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
"""
Binary Tree Views
Compute different "views" of a binary tree — the nodes visible when looking
at the tree from a particular direction.
- **Left view**: first node at each level (leftmost).
- **Right view**: last node at each level (rightmost).
- **Top view**: nodes visible when looking from above.
- **Bottom view**: nodes visible when looking from below (last node at each
horizontal distance).
Reference: https://en.wikipedia.org/wiki/Binary_tree
Complexity (all views):
Time: O(n) — each node is visited once
Space: O(n) — queue / dict storage
"""
from __future__ import annotations
from collections import deque
from algorithms.common.tree_node import TreeNode
def left_view(root: TreeNode | None) -> list[int]:
"""Return the values visible from the left side of the tree.
Args:
root: Root of the binary tree.
Returns:
List of node values, one per level, from the left.
Examples:
>>> from algorithms.common.tree_node import TreeNode
>>> root = TreeNode(1, TreeNode(2, TreeNode(4)), TreeNode(3))
>>> left_view(root)
[1, 2, 4]
"""
if root is None:
return []
result: list[int] = []
queue: deque[TreeNode] = deque([root])
while queue:
level_size = len(queue)
for i in range(level_size):
node = queue.popleft()
if i == 0:
result.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return result
def right_view(root: TreeNode | None) -> list[int]:
"""Return the values visible from the right side of the tree.
Args:
root: Root of the binary tree.
Returns:
List of node values, one per level, from the right.
Examples:
>>> from algorithms.common.tree_node import TreeNode
>>> root = TreeNode(1, TreeNode(2, TreeNode(4)), TreeNode(3))
>>> right_view(root)
[1, 3, 4]
"""
if root is None:
return []
result: list[int] = []
queue: deque[TreeNode] = deque([root])
while queue:
level_size = len(queue)
for i in range(level_size):
node = queue.popleft()
if i == level_size - 1:
result.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return result
def top_view(root: TreeNode | None) -> list[int]:
"""Return the values visible when looking at the tree from above.
Nodes are ordered by horizontal distance from root (left to right).
Args:
root: Root of the binary tree.
Returns:
List of node values visible from the top.
Examples:
>>> from algorithms.common.tree_node import TreeNode
>>> root = TreeNode(1, TreeNode(2, TreeNode(4), TreeNode(5)),
... TreeNode(3, None, TreeNode(6)))
>>> top_view(root)
[4, 2, 1, 3, 6]
"""
if root is None:
return []
# Map: horizontal distance -> first node value seen (BFS ensures top-most)
hd_map: dict[int, int] = {}
queue: deque[tuple[TreeNode, int]] = deque([(root, 0)])
while queue:
node, hd = queue.popleft()
if hd not in hd_map:
hd_map[hd] = node.val
if node.left:
queue.append((node.left, hd - 1))
if node.right:
queue.append((node.right, hd + 1))
return [hd_map[k] for k in sorted(hd_map)]
def bottom_view(root: TreeNode | None) -> list[int]:
"""Return the values visible when looking at the tree from below.
Nodes are ordered by horizontal distance from root (left to right).
When multiple nodes share the same horizontal distance, the last one
encountered in level-order (bottommost) wins.
Args:
root: Root of the binary tree.
Returns:
List of node values visible from the bottom.
Examples:
>>> from algorithms.common.tree_node import TreeNode
>>> root = TreeNode(1, TreeNode(2, TreeNode(4), TreeNode(5)),
... TreeNode(3, None, TreeNode(6)))
>>> bottom_view(root)
[4, 2, 5, 3, 6]
"""
if root is None:
return []
hd_map: dict[int, int] = {}
queue: deque[tuple[TreeNode, int]] = deque([(root, 0)])
while queue:
node, hd = queue.popleft()
hd_map[hd] = node.val # overwrite → keeps bottommost
if node.left:
queue.append((node.left, hd - 1))
if node.right:
queue.append((node.right, hd + 1))
return [hd_map[k] for k in sorted(hd_map)]