LogIn
I don't have account.

How to Find the Right View of a Binary Tree

DevSniper

8 Views

#tree

#binary-tree

#b-tree

#treemap

#depth-first-search

#breadth-first-search

Here's a mistake that's almost too easy to make: you've just solved left view of a binary tree, the interviewer nods and asks for right view next and since the two problems look so similar you reach for the same code, flip a comment or two and submit it. Except if you didn't actually flip the traversal direction, you've just handed back the left view a second time, dressed up as the answer to a different question. This article walks through exactly that trap and how to build a right view solution that's correct for the reason it should be, not by accident.

Problem Statement

You are given the root of a binary tree. Imagine standing to the right of the tree and looking straight across the right view is the set of nodes you'd actually be able to see from that angle.

More precisely: for every level of the tree, the right view keeps only the node that's furthest to the right at that level. Any other node at that same level, hidden behind it from this angle, is left out.

Given the root of a binary tree, return its right view as a list of values, ordered from the topmost level to the bottommost.

For example, for a tree shaped like this:

                  100
                /      \
              200        300
             /              \
           400                500
             \                /
             600            700

The right view is:

100, 300, 500, 700

Understanding the Problem First

Right view groups nodes by level (depth), exactly like left view does it does not involve horizontal distance at all, so it's a different kind of problem from top view or bottom view. The only thing that changes compared to left view is which node wins at each level: instead of the leftmost node, we want the rightmost one.

For the tree above:

  • Depth 0: just 100.
  • Depth 1: 200 and 300. 300 sits further right, so it wins.
  • Depth 2: 400 and 500. 500 sits further right, so it wins.
  • Depth 3: 600 and 700. 600 descends from 400 (on the left side of the tree) while 700 descends from 500 (on the right side), so 700 wins.

So the problem comes down to: for every depth, find the rightmost node, then read those winners off from the shallowest depth to the deepest. That single flipped word leftmost vs. rightmost is deceptively small on paper, but as we're about to see, it needs to be reflected consistently in every part of the solution, not just the final comparison.

Setting Up the Tree

We'll use the tree from above throughout this article.

class TreeNode {
    int val;
    TreeNode left, right;

    TreeNode(int val) {
        this.val = val;
    }
}
public class SampleTree {
    public static TreeNode build() {
        TreeNode n100 = new TreeNode(100);
        TreeNode n200 = new TreeNode(200);
        TreeNode n300 = new TreeNode(300);
        TreeNode n400 = new TreeNode(400);
        TreeNode n500 = new TreeNode(500);
        TreeNode n600 = new TreeNode(600);
        TreeNode n700 = new TreeNode(700);

        n100.left = n200;
        n100.right = n300;
        n200.left = n400;
        n300.right = n500;
        n400.right = n600;
        n500.left = n700;

        return n100;
    }
}

Approach 1: The Naive Attempt (and How It Secretly Stays Left View)

Suppose you've already solved left view and the trick you landed on was: run a DFS, visit left before right and record a node into a depth-keyed map only the first time that depth is reached. That worked because visiting left before right guarantees the first node reached at any depth is the leftmost one.

Now, for right view, it's tempting to just reuse that exact same "first occurrence wins" logic, assuming the depth-tracking part is the important bit and the direction doesn't really matter. It does. If the traversal still visits left before right, "first occurrence per depth" still finds the leftmost node every time the goal changed, but the traversal order that made the old logic correct never did.

Tracing Through It

A standard preorder DFS (root, then left subtree, then right subtree) visits our tree in this order:

100 → 200 → 400 → 600 → 300 → 500 → 700

Recording a value only the first time each depth is reached:

Visit Node Depth Already claimed? Map after this step
1 100 0 no → add {0: 100}
2 200 1 no → add {..., 1: 200}
3 400 2 no → add {..., 2: 400}
4 600 3 no → add {..., 3: 600}
5 300 1 yes → skip unchanged
6 500 2 yes → skip unchanged
7 700 3 yes → skip unchanged

The naive output is:

100, 200, 400, 600

That list isn't nonsense it's a perfectly correct answer, just to the wrong question. It's the left view of this tree. The traversal never stopped visiting left before right, so "first occurrence" kept finding the leftmost node at every depth, exactly as before. Nothing about the depth-tracking logic was broken; the traversal direction underneath it just never got updated to match the new goal.

Approach 2: DFS With the Traversal Order Flipped (Correct)

The fix doesn't require new logic it requires flipping one decision: visit the right child before the left child. Once the traversal itself explores right-first at every branching point, "first occurrence per depth" starts finding the rightmost node instead, for exactly the same structural reason it used to find the leftmost one.

Tracing Through It

With right visited before left, our tree is now traversed in this order:

100 → 300 → 500 → 700 → 200 → 400 → 600

Recording a value only the first time each depth is reached:

Visit Node Depth Already claimed? Map after this step
1 100 0 no → add {0: 100}
2 300 1 no → add {..., 1: 300}
3 500 2 no → add {..., 2: 500}
4 700 3 no → add {..., 3: 700}
5 200 1 yes → skip unchanged
6 400 2 yes → skip unchanged
7 600 3 yes → skip unchanged

Reading the map from the shallowest depth to the deepest:

100, 300, 500, 700

the correct answer.

 
#include <bits/stdc++.h>
using namespace std;

struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int v) : val(v), left(nullptr), right(nullptr) {}
};

void fillLevels(TreeNode* node, int depth, vector<int>& result) {
    if (node == nullptr) return;
    // The first node we reach at a given depth is the rightmost
    // one but only because we visit right before left below
    if (depth == (int)result.size()) {
        result.push_back(node->val);
    }
    fillLevels(node->right, depth + 1, result);
    fillLevels(node->left, depth + 1, result);
}

vector<int> rightView(TreeNode* root) {
    vector<int> result;
    fillLevels(root, 0, result);
    return result;
}

int main() {
    TreeNode* root = SampleTree::build();
    vector<int> result = rightView(root);
    for (int v : result) cout << v << " ";
    cout << endl;
    // Output: 100 300 500 700
    return 0;
}
 
using System;
using System.Collections.Generic;

public class RightViewDFS {
    public static List<int> RightView(TreeNode root) {
        List<int> result = new List<int>();
        FillLevels(root, 0, result);
        return result;
    }
    private static void FillLevels(TreeNode node, int depth, List<int> result) {
        if (node == null) return;
        // The first node we reach at a given depth is the rightmost
        // one but only because we visit right before left below
        if (depth == result.Count) {
            result.Add(node.val);
        }
        FillLevels(node.right, depth + 1, result);
        FillLevels(node.left, depth + 1, result);
    }
    public static void Main(string[] args) {
        TreeNode root = SampleTree.Build();
        List<int> result = RightView(root);
        Console.WriteLine(string.Join(", ", result));
        // Output: 100, 300, 500, 700
    }
}
 
import java.util.*;

public class RightViewDFS {
    public static List<Integer> rightView(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        fillLevels(root, 0, result);
        return result;
    }
    private static void fillLevels(TreeNode node, int depth, List<Integer> result) {
        if (node == null) return;
        // The first node we reach at a given depth is the rightmost
        // one but only because we visit right before left below
        if (depth == result.size()) {
            result.add(node.val);
        }
        fillLevels(node.right, depth + 1, result);
        fillLevels(node.left, depth + 1, result);
    }
    public static void main(String[] args) {
        TreeNode root = SampleTree.build();
        System.out.println(rightView(root));
        // Output: [100, 300, 500, 700]
    }
}
 
def fill_levels(node, depth, result):
    if node is None:
        return
    # The first node we reach at a given depth is the rightmost
    # one but only because we visit right before left below
    if depth == len(result):
        result.append(node.val)
    fill_levels(node.right, depth + 1, result)
    fill_levels(node.left, depth + 1, result)

def right_view(root):
    result = []
    fill_levels(root, 0, result)
    return result

if __name__ == "__main__":
    root = SampleTree.build()
    result = right_view(root)
    print(result)
    # Output: [100, 300, 500, 700]

Notice this is almost character-for-character the same code as a left view solution the only change is the order of the two recursive calls at the bottom. That similarity is exactly what makes the Approach 1 mistake so easy to make and exactly why it's worth understanding why the order matters instead of just memorizing "swap left and right."

Complexity

Value
Time O(n) every node is visited once and the depth check is a constant-time list-size comparison
Space O(h) for the recursion stack, where h is the tree's height

Approach 3: BFS / Level Order Traversal (Optimal)

BFS sidesteps the whole "which child do I visit first" question, because level boundaries are already explicit in a queue-based traversal. Since a level order traversal processes one full level at a time, left to right, the rightmost node at any level is simply the last node dequeued during that level's turn no traversal-direction decision to get backwards in the first place.

Tracing Through It

Processing the tree level by level:

Level Nodes in this level (left to right) Node taken for right view
0 100 100
1 200, 300 300
2 400, 500 500
3 600, 700 700

Final result, read top to bottom:

100, 300, 500, 700
 
#include <bits/stdc++.h>
using namespace std;

struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int v) : val(v), left(nullptr), right(nullptr) {}
};

vector<int> rightView(TreeNode* root) {
    vector<int> result;
    if (root == nullptr) return result;
    queue<TreeNode*> q;
    q.push(root);
    while (!q.empty()) {
        int levelSize = q.size();
        for (int i = 0; i < levelSize; i++) {
            TreeNode* current = q.front();
            q.pop();
            // The last node processed in this level is the rightmost one
            if (i == levelSize - 1) {
                result.push_back(current->val);
            }
            if (current->left != nullptr) {
                q.push(current->left);
            }
            if (current->right != nullptr) {
                q.push(current->right);
            }
        }
    }
    return result;
}

int main() {
    TreeNode* root = SampleTree::build();
    vector<int> result = rightView(root);
    for (int v : result) cout << v << " ";
    cout << endl;
    // Output: 100 300 500 700
    return 0;
}
 
using System;
using System.Collections.Generic;

public class RightViewBFS {
    public static List<int> RightView(TreeNode root) {
        List<int> result = new List<int>();
        if (root == null) return result;
        Queue<TreeNode> queue = new Queue<TreeNode>();
        queue.Enqueue(root);
        while (queue.Count > 0) {
            int levelSize = queue.Count;
            for (int i = 0; i < levelSize; i++) {
                TreeNode current = queue.Dequeue();
                // The last node processed in this level is the rightmost one
                if (i == levelSize - 1) {
                    result.Add(current.val);
                }
                if (current.left != null) {
                    queue.Enqueue(current.left);
                }
                if (current.right != null) {
                    queue.Enqueue(current.right);
                }
            }
        }
        return result;
    }
    public static void Main(string[] args) {
        TreeNode root = SampleTree.Build();
        List<int> result = RightView(root);
        Console.WriteLine(string.Join(", ", result));
        // Output: 100, 300, 500, 700
    }
}
 
import java.util.*;

public class RightViewBFS {
    public static List<Integer> rightView(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if (root == null) return result;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()) {
            int levelSize = queue.size();
            for (int i = 0; i < levelSize; i++) {
                TreeNode current = queue.poll();
                // The last node processed in this level is the rightmost one
                if (i == levelSize - 1) {
                    result.add(current.val);
                }
                if (current.left != null) {
                    queue.add(current.left);
                }
                if (current.right != null) {
                    queue.add(current.right);
                }
            }
        }
        return result;
    }
    public static void main(String[] args) {
        TreeNode root = SampleTree.build();
        System.out.println(rightView(root));
        // Output: [100, 300, 500, 700]
    }
}
 
from collections import deque

def right_view(root):
    result = []
    if root is None:
        return result
    queue = deque([root])
    while queue:
        level_size = len(queue)
        for i in range(level_size):
            current = queue.popleft()
            # The last node processed in this level is the rightmost one
            if i == level_size - 1:
                result.append(current.val)
            if current.left is not None:
                queue.append(current.left)
            if current.right is not None:
                queue.append(current.right)
    return result

if __name__ == "__main__":
    root = SampleTree.build()
    result = right_view(root)
    print(result)
    # Output: [100, 300, 500, 700]

Note that unlike the DFS version, this BFS solution enqueues children in the normal left-then-right order there's no need to flip anything, since we're picking the last node processed per level rather than relying on visiting order to determine "first."

Complexity

Value
Time O(n) every node is enqueued and dequeued exactly once
Space O(n) for the queue in the worst case, when the tree's widest level holds close to n / 2 nodes

Comparing All Approaches

Approach Time Complexity Space Complexity Core Idea
Naive DFS (buggy) O(n) O(h) Left-before-right traversal with "first occurrence wins" correctly finds the leftmost node per depth, which is left view, not right view
DFS with Traversal Flipped O(n) O(h) Visit right before left, then take the first occurrence per depth now correctly finds the rightmost node
BFS / Level Order Optimal O(n) O(n) Take the last node dequeued at each level directly no traversal-direction decision needed

n = number of nodes, h = height of the tree.

Just like left view, right view groups by depth rather than horizontal distance, so there's no need for a TreeMap or any sorting step here both correct solutions run in clean O(n), with no logarithmic overhead. The real risk in this problem isn't complexity, it's direction: DFS-based solutions are entirely dependent on visiting children in the correct order and it's easy to carry that assumption over incorrectly from a similar problem.

Key Takeaways

  1. Similar problems can share logic and still need a real change, not a relabel. The "first occurrence wins" trick is correct for both left and right view but only once it's paired with the traversal direction that actually matches the question being asked.
  2. A wrong answer that looks plausible is the hardest kind to catch. Approach 1 doesn't crash and doesn't look obviously broken it just quietly answers a different, equally valid-looking problem.
  3. BFS removes an entire class of "which order did I mean" bugs. Because level boundaries are explicit in a queue, there's no traversal-direction assumption to get backwards in the first place.
  4. When adapting a solution from a near-identical problem, isolate exactly which piece encoded the old assumption. Here, that piece was two lines of recursive calls everything else about the "first occurrence per depth" logic carried over correctly.

Frequently Asked Questions

1. What is the difference between right view and left view of a binary tree?

Both group nodes by depth and keep exactly one node per level, but left view keeps the leftmost node at each level while right view keeps the rightmost one. A DFS solution for one becomes a solution for the other only if the traversal's child-visiting order is also flipped.

2. Why does reusing left view code for right view sometimes still return the left view?

If only the "first occurrence per depth" comparison is copied over but the traversal still visits the left child before the right child, the first node reached at each depth remains the leftmost one the traversal order is what actually determines which side wins, not the comparison logic alone.

3. Does finding the right view require tracking horizontal distance?

No. Like left view, right view depends only on depth and left-to-right position within a level. Horizontal distance is only needed for top view and bottom view, which group nodes differently.

4. What is the time complexity of finding the right view of a binary tree?

Both the correct DFS approach (visiting right before left) and the BFS approach run in O(n) time, where n is the number of nodes. No TreeMap or sorting is required, since depth values are already sequential.

5. Is BFS or DFS better for solving right view?

Both run in O(n) time. BFS is often considered safer here because level boundaries are explicit, so there's no traversal-direction assumption to get wrong. The DFS approach is equally correct, but only once the right-before-left visiting order is deliberately chosen rather than left unchanged from a left view solution.

Related Articles

Responses (0)

Write a response

CommentHide Comments

No Comments yet.