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]Looking at a tree from the side, the node you see at a given depth is the one furthest right on that level — everything else on that level is hidden behind it. So the answer is one node per level, and the only question is which.
The first instinct is usually wrong in an instructive way: follow the right children down from the root. That fails as soon as the right spine ends early. If the root's right child has no children of its own but the left subtree runs three levels deeper, those deeper levels are still visible — the rightmost node there simply comes from the left side of the tree. Visibility is a property of position on a level, not of which pointer slot a node occupies.
Once the answer is phrased as "the last node of each level," the level-by-level walk from Binary Tree Level Order Traversal delivers it directly. Within a level, the queue hands nodes over strictly left to right, so the final node of the frozen level_size iterations is the rightmost one. Record that, discard the rest.
if root is None: return []
out, queue = [], deque([root])
while queue:
n = len(queue) # frozen level size, exactly as before
for i in range(n):
node = queue.popleft()
if i == n - 1: # the last node of this level is the visible one
out.append(node.val)
if node.left: queue.append(node.left)
if node.right: queue.append(node.right)
return outNothing about the traversal changed — only the rule for what gets recorded. The left side view is the same code with i == 0.
There is a second solution worth knowing, because it costs different memory. Walk the tree depth-first but visit the right child before the left, carrying the current depth as a parameter. Then the first node ever reached at any given depth is the rightmost node of that depth.
The argument: visiting right-first means that among all nodes at a fixed depth, the walk reaches them in right-to-left order — at every branching point above them, the right-hand descendants are explored before the left-hand ones. So the first arrival at a new depth is the rightmost node there. Record a node only when the recorded list is shorter than the depth we have reached, which is exactly the test for "this depth has not been seen yet."
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 rightmost node here
walk(node.right, depth + 1) # right FIRST
walk(node.left, depth + 1)
walk(root, 0)Now the second example, root 1 with children 2 and 3, where 2 has a left child 4. At level 2 the queue holds only 4, so n = 1 and 4 is at index n - 1 — recorded, despite being a left child and despite the right subtree having nothing at that depth. This is exactly the case the naive "walk the right spine" idea gets wrong.
Both solutions visit every node once: O(N) time. Their memory differs — the queue version costs O(W) for the widest level, the depth-first version O(H) for the recursion stack. On a wide bushy tree, prefer depth-first; on a deep chain, prefer the queue. That is the same trade laid out in Level Order Traversal, and this problem is a clean place to see both sides of it in working code.
The habit to build: when a problem asks for "the visible" or "the first" or "the extreme" something per level, the traversal is almost certainly untouched — only the selection rule changes. Level Order records everything, Zigzag reorders the recording, Side View filters it down to one. Recognising which of the three slots a new problem touches — traversal, ordering, or selection — is usually the entire solution.
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.