title: Binary Tree Right Side View
slug: binary-tree-right-side-view
difficulty: medium
leetcode_id: 199
leetcode_url: https://leetcode.com/problems/binary-tree-right-side-view/
categories:
  - trees
patterns:
  - bfs
  - dfs
  - tree-traversal

description: |
  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*.

constraints: |
  - The number of nodes in the tree is in the range `[0, 100]`
  - `-100 <= Node.val <= 100`

examples:
  - input: "root = [1,2,3,null,5,null,4]"
    output: "[1,3,4]"
    explanation: "Standing on the right side, you see node 1 at level 0, node 3 at level 1 (it's rightmost), and node 4 at level 2 (it's rightmost even though it's a child of node 3)."
  - input: "root = [1,2,3,4,null,null,null,5]"
    output: "[1,3,4,5]"
    explanation: "At each level, you see the rightmost node: 1, then 3, then 4 (left child of 2, but rightmost at that level since 3 has no children at that depth), then 5."
  - input: "root = [1,null,3]"
    output: "[1,3]"
    explanation: "The tree only has right children, so you see both nodes from the right side."
  - input: "root = []"
    output: "[]"
    explanation: "An empty tree has no nodes to see."

explanation:
  intuition: |
    Imagine you're standing to the right of a building where each floor has rooms arranged left to right. From your vantage point, you can only see the **rightmost room on each floor** — the other rooms are hidden behind it.

    A binary tree works similarly when viewed from the right side. At each *level* (or depth) of the tree, only the **rightmost node** is visible. All other nodes at that level are obscured.

    The key insight is that "right side view" means collecting **one node per level** — specifically, the last node encountered when traversing that level from left to right. This naturally suggests a **level-order traversal** (BFS) where we process nodes level by level and remember the last node at each level.

    Alternatively, with DFS, we can traverse the tree visiting the right subtree before the left. The first node we encounter at each new depth becomes the visible node from the right.

  approach: |
    We solve this using a **Level-Order Traversal (BFS)** approach:

    **Step 1: Handle edge case**

    - If `root` is `None`, return an empty list — there are no nodes to see

    &nbsp;

    **Step 2: Initialise data structures**

    - `result`: Empty list to store the right side view
    - `queue`: Initialise with the root node for BFS traversal

    &nbsp;

    **Step 3: Process level by level**

    - While the queue is not empty, determine the number of nodes at the current level (`level_size`)
    - Iterate through all nodes at this level
    - For each node, add its children (left then right) to the queue for the next level
    - The **last node** processed in each level is the rightmost — add its value to the result

    &nbsp;

    **Step 4: Return the result**

    - After processing all levels, `result` contains the right side view from top to bottom

    &nbsp;

    The BFS approach naturally processes nodes left-to-right at each level, so the last node we see at each level is exactly what we'd see from the right side.

  common_pitfalls:
    - title: Confusing Right Side View with Right Children Only
      description: |
        A common mistake is thinking the right side view only includes nodes that are right children. This is incorrect.

        Consider a tree where node 2 is a left child but has no sibling on the right at its level — node 2 would be visible from the right side. For example, in `[1,2,null]`, both 1 and 2 are visible from the right even though 2 is a left child.

        The right side view includes the **rightmost node at each level**, regardless of whether it's a left or right child.
      wrong_approach: "Only collecting right children"
      correct_approach: "Collecting the last node at each level via BFS"

    - title: Not Processing Full Levels in BFS
      description: |
        When using BFS, you must process **all nodes at a level** before moving to the next level. A common bug is to simply take the last element from the queue without tracking level boundaries.

        The fix is to record `level_size = len(queue)` at the start of each level and iterate exactly that many times. This ensures you correctly identify where each level ends.
      wrong_approach: "Processing queue without tracking level boundaries"
      correct_approach: "Using level_size to process exactly one level at a time"

    - title: Wrong DFS Order
      description: |
        When using DFS for this problem, you must visit the **right subtree before the left**. If you visit left first, the first node you see at each depth will be the leftmost, not the rightmost.

        The DFS approach works by recording the first node encountered at each new depth — so visiting right-first ensures we see the right side view.
      wrong_approach: "DFS visiting left subtree before right"
      correct_approach: "DFS visiting right subtree before left"

  key_takeaways:
    - "**Level-order traversal** (BFS) is ideal when you need to process nodes level by level or find the first/last node at each depth"
    - "**Right side view = rightmost at each level**, not just right children — understanding this distinction is crucial"
    - "**DFS alternative**: Visit right-before-left and track depth to achieve the same result with O(h) space instead of O(w)"
    - "This pattern extends to **left side view** (take first node per level) and other level-based tree problems"

  time_complexity: "O(n). We visit each node exactly once during the BFS traversal."
  space_complexity: "O(w) where w is the maximum width of the tree. In the worst case (a complete binary tree), the last level can have up to n/2 nodes, so this is O(n) in the worst case."

solutions:
  - approach_name: BFS Level-Order Traversal
    is_optimal: true
    code: |
      from collections import deque
      from typing import Optional

      class TreeNode:
          def __init__(self, val=0, left=None, right=None):
              self.val = val
              self.left = left
              self.right = right

      def right_side_view(root: Optional[TreeNode]) -> list[int]:
          # Edge case: empty tree
          if not root:
              return []

          result = []
          queue = deque([root])

          while queue:
              # Number of nodes at current level
              level_size = len(queue)

              for i in range(level_size):
                  node = queue.popleft()

                  # Add children for next level (left before right)
                  if node.left:
                      queue.append(node.left)
                  if node.right:
                      queue.append(node.right)

                  # Last node in level is the rightmost (visible from right)
                  if i == level_size - 1:
                      result.append(node.val)

          return result
    explanation: |
      **Time Complexity:** O(n) — Every node is visited exactly once.

      **Space Complexity:** O(w) — The queue holds at most one level of nodes. For a complete binary tree, the widest level has ~n/2 nodes.

      We use BFS to traverse level by level. At each level, we process all nodes left-to-right, adding their children to the queue. The last node we process at each level is the rightmost, which is what we'd see from the right side.

  - approach_name: DFS Right-First Traversal
    is_optimal: false
    code: |
      from typing import Optional

      class TreeNode:
          def __init__(self, val=0, left=None, right=None):
              self.val = val
              self.left = left
              self.right = right

      def right_side_view(root: Optional[TreeNode]) -> list[int]:
          result = []

          def dfs(node: Optional[TreeNode], depth: int) -> None:
              if not node:
                  return

              # First time reaching this depth? This node is visible from right
              if depth == len(result):
                  result.append(node.val)

              # Visit right subtree first to see rightmost nodes first
              dfs(node.right, depth + 1)
              dfs(node.left, depth + 1)

          dfs(root, 0)
          return result
    explanation: |
      **Time Complexity:** O(n) — Every node is visited exactly once.

      **Space Complexity:** O(h) — The recursion stack uses space proportional to the tree height. For a balanced tree h = log(n), for a skewed tree h = n.

      We use DFS, visiting the right subtree before the left. The first time we reach a new depth, that node must be the rightmost at that level (since we explore right-first). We track this by comparing `depth` with `len(result)`.

      This approach uses less space than BFS for tall, narrow trees but more space for short, wide trees.
