Binary Tree Right Side View: Last Node at Each Level
Given the root of a binary tree, imagine yourself standing on the right side of it. Return the values of the nodes you can see ordered from top to bottom. This is LeetCode 199: Binary Tree Right Side View.
For example, given root = [1, 2, 3, null, 5, null, 4], the output is [1, 3, 4]. From the right side, node 2 is hidden behind node 3, and node 5 is hidden behind node 4.
Approach
The right side view of a binary tree is the last node at each level when you read left to right. If you already know how to do a level order traversal (LeetCode 102), this problem is a small reduction on top.
Run BFS level by level. At each level, snapshot the queue size, drain all nodes in that level, and keep track of the last value you dequeue. After the inner loop finishes, that last value is the rightmost node visible from the right side. Append it to the result.
You do not need to reverse anything or track direction. You just need the last element from each level.
The Python solution
from collections import deque
def right_side_view(root):
if not root:
return []
result = []
queue = 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
Here is what each part does:
queue = deque([root])seeds the queue with the root node. Level 0 always has exactly one node.level_size = len(queue)captures how many nodes are in the current level before draining begins.if i == level_size - 1checks whether this is the last node in the current level. If so, it is the rightmost visible node from the right side.- The inner loop dequeues all nodes at the current level and enqueues their children for the next level. Only the final node's value gets appended to the result.
The check i == level_size - 1 is the only difference between this solution and a standard level order traversal. Instead of collecting every node at a level, you collect just the last one. This same "last element extraction" idea works any time you need only a specific position within a BFS level.
Visual walkthrough
Trace BFS through the tree [1, 2, 3, null, 5, null, 4]. Watch how the queue drains each level and only the last node dequeued per level enters the result.
Step 1: Initialize. Push root into the queue.
Queue: [1]
Last node: -
Result: []
The queue holds the root. About to process level 0.
Step 2: Process Level 0. Dequeue 1, enqueue children.
Queue: [2, 3]
Last node: 1 (only node at this level)
Result: [1]
Node 1 is the last (and only) node at level 0, so it goes into the result.
Step 3: Process Level 1. Dequeue 2, then 3.
Queue: [5, 4]
Last node: 3 (rightmost at this level)
Result: [1, 3]
Node 3 is the last node dequeued at level 1. That makes it the right side view node.
Step 4: Process Level 2. Dequeue 5, then 4.
Queue: []
Last node: 4 (rightmost at this level)
Result: [1, 3, 4]
Node 4 is the last node dequeued at level 2. Both are leaves, so nothing enters the queue.
Step 5: Queue is empty. Done!
Queue: []
Last node: -
Result: [1, 3, 4]
All nodes visited. The result contains the last node from each level: [1, 3, 4].
At every level, BFS processes nodes left to right. The last node it dequeues at each level is the one visible from the right side. Node 1 is alone at level 0. At level 1, node 3 comes after node 2. At level 2, node 4 comes after node 5. The result builds up as [1, 3, 4].
Complexity analysis
| Metric | Value | Why |
|---|---|---|
| Time | O(n) | Every node is enqueued and dequeued exactly once |
| Space | O(n) | The queue can hold up to n/2 nodes (the widest level of a complete binary tree) |
The space is O(n) in the worst case because the bottom level of a complete binary tree contains roughly half of all nodes. For a skewed tree (a single chain), the queue never holds more than one node, but the worst case is still O(n).
The result list stores at most one value per level, so it uses O(h) space where h is the height of the tree. The queue dominates the auxiliary space.
Building blocks
This problem is built on two reusable patterns:
1. BFS level-by-level processing. The template snapshots the queue size at the start of each level and drains exactly that many nodes:
from collections import deque
def bfs_by_level(root):
queue = deque([root])
while queue:
level_size = len(queue)
for _ in range(level_size):
node = queue.popleft()
for child in [node.left, node.right]:
if child:
queue.append(child)
2. Last-element extraction. Instead of collecting all values at a level, you only keep the final one. The check i == level_size - 1 inside the inner loop does exactly that.
These two building blocks combine cleanly. The BFS template gives you level boundaries. Last-element extraction picks out the right side view from each level. Once you have both patterns internalized, this problem requires no new ideas.
Edge cases
- Empty tree (
rootis None): return an empty list[]. The guard clause at the top handles this. - Single node (no children): return
[root.val]. The root is the only node at level 0, so it is the last (and only) node dequeued. - Left-only tree (every node has only a left child): each level has one node, and that node is the left child. Since it is the only node at its level, it is still the "last" node dequeued. The right side view of a left-only tree is every node in the chain, top to bottom. BFS handles this without any special logic.
From understanding to recall
You just read through a clean BFS solution and saw that the right side view comes down to keeping the last node at each level. It makes sense right now. But in an interview next month, will you remember whether to check i == level_size - 1 or i == 0? Will you reconstruct the BFS template from scratch without hesitation?
Understanding a pattern and being able to reproduce it under pressure are different skills. Spaced repetition bridges that gap. You practice typing the BFS level-by-level template from memory at increasing intervals. First after a day, then three days, then a week. Each repetition reinforces the level-size snapshot, the last-element check, and the queue mechanics until the pattern is automatic.
BFS level-by-level is one of roughly 60 reusable building blocks that cover hundreds of LeetCode problems. Drilling them individually with spaced repetition is far more effective than grinding random problems and hoping the patterns stick.
Related posts
- Binary Tree Level Order Traversal - The base BFS level-by-level pattern that this problem reduces to
- Binary Tree Zigzag Level Order Traversal - Another BFS level-by-level variation that alternates direction instead of extracting the last element