Binary Tree Left/Right Side View
Stand to the right of the tree and look at it horizontally: at each depth you see exactly one node, the one furthest right on that level. Return those values ordered from the top of the tree downward. The left side view is the mirror question, taking the leftmost node of each level. The result has exactly one entry per level, and an empty tree returns an empty list.
- The number of nodes in the tree is in the range [0, 100]
- -100 <= Node.val <= 100
- Exactly one value per level, ordered top to bottom
- Visibility is by level position, not by which child slot a node occupies
root = [1,2,3,null,5,null,4], right side view[1,3,4]root = [1,2,3,4], right side view[1,3,4]root = [1,2], right side view[1,2]root = [1,2,3,4,null,null,5], left side view[1,2,4]Look at the tree from one side and read off what you see. From the right you see the rightmost node of each level; from the left, the leftmost. Everything between is hidden. Either way the answer is one value per level — the two views are perfect mirrors of each other.
1 left sees 1 | right sees 1
/ \
2 3 left sees 2 | right sees 3
\ \
5 4 left sees 5 | right sees 4
left side view: [1, 2, 5]
right side view: [1, 3, 4]First instinct — "just follow the right children down for the right view" (or left children for the left view) — is a trap. If that spine ends early but the other subtree runs deeper, those deeper levels are still visible; the edge node there just comes from the opposite side:
1 right sees 1
/ \
2 3 right sees 3
/
4 right sees 4 (a LEFT node — the right spine already ended!)
/
5 right sees 5
right side view: [1, 3, 4, 5]
"just follow right children": [1, 3] <- wrongly stops, misses 4 and 5Visibility is about position on a level, not which child slot a node sits in.
A level-by-level sweep hands both over. Sweep with a queue: freeze the level's size, pull exactly that many nodes; the queue gives them left to right, so within each level the first pulled is the leftmost (the left view) and the last pulled is the rightmost (the right view). Record the one you want, drop the rest.
if root is None: return []
out, queue = [], deque([root])
while queue:
n = len(queue) # frozen level size
for i in range(n):
node = queue.popleft()
want = (i == 0) if left_view else (i == n - 1)
if want: # first node for left view, last for right
out.append(node.val)
if node.left: queue.append(node.left)
if node.right: queue.append(node.right)
return outThe two views are one line apart — i == 0 versus i == n - 1. Nothing about the walk changes, only which node you record.
There's a depth-first version that costs O(H) instead of O(W) — better on wide trees. For the right view, visit the right child first, carrying the depth; then the first node reached at any new depth is the rightmost there (at every fork above them, right descendants run before left). Record a node only when the answer list is still shorter than the depth reached — that's the "this depth is brand new" test. For the left view, mirror it: visit the left child first.
out = []
def walk(node, depth):
if node is None: return
if depth == len(out): # first time we reach this depth
out.append(node.val) # so this is the edge node on this side
walk(node.right, depth + 1) # right FIRST for right view (swap for left view)
walk(node.left, depth + 1)
walk(root, 0)Both visit every node once: O(N) time. Memory differs — BFS costs O(W) (widest level), DFS costs O(H) (recursion depth). Wide bushy tree → DFS; deep chain → BFS. The habit: when a problem wants "the visible / first / extreme" node per level, the traversal is untouched — only the selection rule changes.
Perspective Analysis
Simulate Left vs. Right visibility
Algorithm Rules
- Depth Tracking: Use a Level variable to track vertical position.
- Visibility Rule: First node visited at any depth is part of the view.
- Priority Search: Prioritize Right child to see Right Side.
level == result.size(), it's the first time we've reached this depth.