LeetCode #199 Medium

Binary Tree Right Side View

Return the values visible from the right side — the last node of each level.

treebfsdfs
Open on LeetCode ↗
02

Intuition

Level order traversal, but keep only each level's final element. Or DFS right-first, recording the first node reached at each new depth — both express 'rightmost per level'.

How to spot this pattern

Level-order with a queue is the obvious route, but DFS works too if you visit the right child first: then the first node reached at each depth is the rightmost one. Comparing depth == len(view) is a neat way to ask "is this the first time I've been this deep?" without tracking levels explicitly.

03

Approach

1

BFS take

Standard level-order; when the per-level loop ends, the last popped value is the visible one.

2

DFS take

Visit right before left, carrying depth. If depth == len(view), this node is the first seen at that depth → rightmost.

3

Pick by constraint

BFS is iterative and obvious; DFS is shorter and O(h) space on balanced trees.

04

Solution & live demo

1class Solution:
2 def rightSideView(self, root):
3 view = []
4 def dfs(node, depth):
5 if not node: return
6 if depth == len(view):
7 view.append(node.val)
8 dfs(node.right, depth + 1) # right first
9 dfs(node.left, depth + 1)
10 dfs(root, 0)
11 return view
05

Common pitfalls

Recursing left before right

✗ Wrong
dfs(node.left, depth + 1)
dfs(node.right, depth + 1)
✓ Right
dfs(node.right, depth + 1)
dfs(node.left, depth + 1)

The whole method rests on the first arrival at each depth being the rightmost node. Going left first records the left side view instead — the code looks right and the answer is silently mirrored.

Overwriting the stored value at each depth

✗ Wrong
if depth < len(view):
    view[depth] = node.val
else:
    view.append(node.val)
✓ Right
if depth == len(view):
    view.append(node.val)

With right-first ordering the first node seen at a depth is already the correct one, so later nodes at that depth must be ignored. Overwriting replaces it with a node further left.

Tracking depth with a shared mutable counter

✗ Wrong
self.depth += 1
dfs(node.right)
self.depth -= 1
✓ Right
dfs(node.right, depth + 1)

It's an extra pair of mutations to keep balanced across every branch and early return. Depth is naturally per-path, so it belongs in the call argument where the language unwinds it for you.

06

Edge cases

Left-heavy levels

A left node can be visible if the right subtree is shallower — level-based logic handles it (unlike 'just walk right').

Empty tree

[].

07

Complexity

Time
O(n)
Space
O(h)
Right-first DFS; first arrival per depth wins.