A checkout-routing console stores a binary split tree: each node is a question (geo, then rail, then issuer). The SRE wall on the east side of the NOC paints one chip per depth — whatever sits at the right edge of that floor — so a reviewer sees the tree’s silhouette without every sibling. The intern version ran full Level Order, kept every floor list, then took level.get(level.size() - 1). A dozen routes painted instantly. A routing tree with tens of thousands of nodes still returned, but the floor lists were furniture a last-poll already gives you.
Right Side View asks for the last live node on each depth, top to bottom. The binary tree post owns level-order as a layout walk. The BFS post owns why the frontier is a FIFO ArrayDeque. Level Order is the same size snapshot; they collect the whole floor, you keep only the last poll. Do not paste a graph seen set or a shortest-path argument from that post.
The problem
Given the root of a binary tree, return the values visible standing on the right: one value per depth, top to bottom. An empty tree returns an empty list. A single node returns [val].
final class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int val) {
this.val = val;
}
}
Sample trees and the right-edge return. A missing right child does not hide a left-subtree node that is the only live node on that floor.
8
/ \
3 10
/ \
9 14
→ [8, 10, 14]
8
/ \
3 10
\
5
→ [8, 10, 5]
(root = null) → []
[1] → [1]
left spine 8-3-5 → [8, 3, 5]
Note: Visible-from-the-right is the last live node at that depth, left-to-right enqueue order. It is not “always follow right.” A single node is [val], not [[val]].
Collect every floor, then take the last value is the honest brute force
Run the Level Order drain, keep every floor list, then take the last value of each. Correct. Extra lists.
List<Integer> rightSideFromFloors(List<List<Integer>> floors) {
List<Integer> ans = new ArrayList<>();
for (List<Integer> level : floors) {
ans.add(level.get(level.size() - 1));
}
return ans;
}
At a dozen nodes this is a rounding error. At tens of thousands you paid a floor list for a question the inner loop already answers: is this poll the last of the snapshot?
Snapshot size, keep the last poll
Offer the root. While the queue is not empty, record int size = q.size() — that many polls are this floor — then loop that count: poll, offer left then right when they exist, and when i == size - 1 append the value. After the inner loop, that last poll is the right-side node.
The right-side node is the last live node on the floor, not the right spine. Snapshot size before you offer children. A single while (!q.isEmpty()) that offers as it polls flattens the tree; the count is the grouping.
q: [8]
size=1 poll 8 (i==0 last) offer 3, 10 view [8]
q: [3, 10]
size=2 poll 3 (no kids)
poll 10 (i==1 last) offer 9, 14 view [8, 10]
q: [9, 14]
size=2 poll 9
poll 14 (i==1 last) view [8, 10, 14]
q: []
→ [8, 10, 14]
The Java is that walk. Use Deque and ArrayDeque, not java.util.Stack, not ArrayList.remove(0). Skip null children — ArrayDeque refuses null, and this prompt does not want holes.
List<Integer> rightSideView(TreeNode root) {
List<Integer> ans = new ArrayList<>();
if (root == null) {
return ans;
}
Deque<TreeNode> q = new ArrayDeque<>();
q.offer(root);
while (!q.isEmpty()) {
int size = q.size();
for (int i = 0; i < size; i++) {
TreeNode node = q.poll();
if (i == size - 1) {
ans.add(node.val);
}
if (node.left != null) {
q.offer(node.left);
}
if (node.right != null) {
q.offer(node.right);
}
}
}
return ans;
}
Time is O(n) — each node is offered once and polled once. Space is O(w) for the queue, w being the widest floor (plus the answer list, which is the output). A perfect tree’s last floor is about n/2; a spine’s queue stays O(1). Do not quote a graph seen set; there is nothing to mark.
Note: Return [] for a null root before you offer. Offering null throws on ArrayDeque.
What interviewers usually poke next
- DFS, prefer right. Recurse right then left. The first visit at each depth (
depth == ans.size()) is the rightmost node; record it and skip later visits at that depth. Correct. A spine isO(n)frames. They may ask this after the queue walk; it is not the default. - Zigzag. Same drain; reverse every other floor, or poll from the opposite end. Different return. Future path
/interview/trees/medium/binary-tree-zigzag-level-order-traversal/. - Left Side View. Same snapshot; keep the first poll of each floor (
i == 0). Same trap in reverse: it is not “always followleft.” - Why no
seen? A tree has no parent pointer back and at most two children. Mark-on-enqueue is the graph post’s cycle filter. Pasting it here is cargo.
You are done with this problem when you can snapshot q.size(), drain that many, keep the last poll, walk [8, 10, 14] out loud, and say why a missing right child still shows a left node that is alone on that floor.