easyleetcodeNot Started

Binary Tree Left View

A curated StudyFlow practice problem with comprehensive editorial and multi-language solutions.

Solve on leetcode
Lesson

Problem Statement

Given the root of a binary tree, imagine yourself standing on the left side of it, return the values of the nodes you can see ordered from top to bottom.

For each level of the tree, only the leftmost visible node should be included in the answer.

Example 1 · Example 1: Standard Tree:

Input: root = [1, 2, 3, null, 4, null, 5] Tree: 1 / \ 2 3 \ \ 4 5
Output: [1, 2, 4]
Explanation: Level 0 leftmost: 1. Level 1 leftmost: 2. Level 2 leftmost: 4 (node 5 is hidden behind 4).

Example 2 · Example 2: Left-leaning tree:

Input: root = [1, 2, null, 3] Tree: 1 / 2 / 3
Output: [1, 2, 3]
Explanation: All nodes are on the left spine.

Constraints:

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

What You'll Learn

Key principles and algorithmic techniques you will master from this problem:

  • Understand how tree views relate to level order traversals.
  • Implement left view using both BFS queue and DFS recursion.
  • Recognize the invariant: depth == result.length signifies first time visiting that level.

Pattern Recognition Trigger

How to instantly recognize this algorithmic pattern when encountering unseen interview questions:

Signals to Look For:

  • View from left side.
  • First visible node at every level.
  • Level order with leftmost selection.

Algorithmic Decision Tree:

  • If root is null -> return [].
  • DFS: dfs(node, depth): if depth == res.size() -> res.push_back(node.val); dfs(left, depth+1); dfs(right, depth+1).
  • BFS: For level size L, push queue.front().val if i == 0.

Connected Patterns:

Binary Tree Right Side ViewBinary Tree Level Order TraversalTop View of Binary Tree

1. Full Level Order Traversal (Store All)

Intuition

Perform standard BFS collecting all node values into levels array levels[level][]. Then iterate through levels and take levels[i][0].

When to apply: Basic baseline check.

Algorithm

  1. Step 1: If root == null return [].
  2. Step 2: Run BFS with queue, collecting all node values level-by-level into a 2D array.
  3. Step 3: Extract the 0-th element of each level array.
  4. Step 4: Return the result list.
C++ SOLUTIONCLEAN & OPTIMIZED
1#include <iostream>
2#include <vector>
3#include <string>
4#include <algorithm>
5using namespace std;
6
7class Solution {
8public:
9 vector<int> leftView(TreeNode* root) {
10 if (!root) return {};
11 vector<vector<int>> levels;
12 queue<TreeNode*> q;
13 q.push(root);
14 while (!q.empty()) {
15 int sz = q.size();
16 vector<int> cur;
17 for (int i = 0; i < sz; ++i) {
18 TreeNode* node = q.front(); q.pop();
19 cur.push_back(node->val);
20 if (node->left) q.push(node->left);
21 if (node->right) q.push(node->right);
22 }
23 levels.push_back(cur);
24 }
25 vector<int> res;
26 for (auto& lvl : levels) res.push_back(lvl[0]);
27 return res;
28 }
29};
30
31int main() {
32 // Sample driver execution
33 cout << "Execution completed successfully." << endl;
34 return 0;
35}
36

Time & Space Complexity

  • Time complexity: O(n) — All n nodes are stored in the 2D levels array.
  • Space complexity: O(n) — The 2D list stores all n nodes.

2. BFS with Queue (Direct First Element Extraction)

Intuition

Iterate level by level with a queue. For each level loop from i = 0 to size - 1. If i == 0, push node.val to result. Push children as usual.

When to apply: When using queue-based iteration without excess 2D array storage.

Algorithm

  1. Step 1: If root == null return [].
  2. Step 2: Enqueue root into queue.
  3. Step 3: While queue is not empty, get current level size = queue.size().
  4. Step 4: For each node at index i: if i == 0, append node.val to result. Enqueue left and right children.
  5. Step 5: Return result.
C++ SOLUTIONCLEAN & OPTIMIZED
1#include <iostream>
2#include <vector>
3#include <string>
4#include <algorithm>
5using namespace std;
6
7class Solution {
8public:
9 vector<int> leftView(TreeNode* root) {
10 if (!root) return {};
11 vector<int> res;
12 queue<TreeNode*> q;
13 q.push(root);
14 while (!q.empty()) {
15 int sz = q.size();
16 for (int i = 0; i < sz; ++i) {
17 TreeNode* node = q.front(); q.pop();
18 if (i == 0) res.push_back(node->val);
19 if (node->left) q.push(node->left);
20 if (node->right) q.push(node->right);
21 }
22 }
23 return res;
24 }
25};
26
27int main() {
28 // Sample driver execution
29 cout << "Execution completed successfully." << endl;
30 return 0;
31}
32

Time & Space Complexity

  • Time complexity: O(n) — Visits every node once.
  • Space complexity: O(w) — Queue holds at most maximum width w of tree (up to n/2 nodes).

3. Recursive Preorder DFS (Root -> Left -> Right)

Intuition

By visiting Root -> Left -> Right, we visit the leftmost branch of each level before any right nodes. Whenever depth == res.length, we know we are visiting this level for the very first time, so we add node.val to res.

When to apply: Optimal memory solution: requires only O(h) recursion stack instead of queue memory.

Algorithm

  1. Step 1: Helper function dfs(node, depth, res).
  2. Step 2: If node == null return.
  3. Step 3: If depth == res.size(), add node.val to res.
  4. Step 4: Recurse dfs(node.left, depth + 1, res).
  5. Step 5: Recurse dfs(node.right, depth + 1, res).

Left View BFS Trace for root = [1, 2, 3, null, 4]

2 of 2 questions left today
Step 1 / 2
Trace timeline50% explored
Current operationSTEP 1 OF 2
Step 1: Level 0 has root (1)
Visual state
Values and pointers at this exact step
tree
Root
1 (Visible)
L
2
R
3

Node order shown; add connections to display explicit tree edges.

level 0: 1
Check / comparison
Level 0: leftmost = 1
Decision / next transition
Add 1 to result. Enqueue [2, 3].
Why this step matters

Step 1: Level 0 has root (1). It is index 0 of level 0 -> record 1 into left view. Enqueue children 2 and 3.

Step 1 / 2
C++ SOLUTIONCLEAN & OPTIMIZED
1#include <iostream>
2#include <vector>
3#include <string>
4#include <algorithm>
5using namespace std;
6
7class Solution {
8public:
9 void dfs(TreeNode* node, int depth, vector<int>& res) {
10 if (!node) return;
11 if (depth == res.size()) {
12 res.push_back(node->val);
13 }
14 dfs(node->left, depth + 1, res);
15 dfs(node->right, depth + 1, res);
16 }
17 vector<int> leftView(TreeNode* root) {
18 vector<int> res;
19 dfs(root, 0, res);
20 return res;
21 }
22};
23
24int main() {
25 // Sample driver execution
26 cout << "Execution completed successfully." << endl;
27 return 0;
28}
29

Time & Space Complexity

  • Time complexity: O(n) — Visits every node once.
  • Space complexity: O(h) — Recursion call stack equals height h of the tree (O(log n) balanced, O(n) skewed).

Approach Comparison Matrix

Side-by-side comparison of time, space, and algorithmic trade-offs across each approach:

ApproachTimeSpaceCore IdeaTrade-off / Bottleneck
1.Full Level Order StorageO(n)O(n)Collect all levels completely, pick first element.Memory waste.
2.BFS Direct First ElementO(n)O(w)Queue BFS, grab element at index 0 for each level.Queue memory at maximum level width.
3.Preorder DFS with Depth CheckOptimalO(n)O(h)Root -> Left -> Right recursion; append when depth == res.length.None. Gold standard.

Common Pitfalls & Crucial Edge Cases

Crucial Edge Cases to Validate:

  • Empty tree: Returns [].
  • Single node: Returns [root.val].
  • Right-skewed tree: Every right child is the only node at that level, so all right children are visible.
  • Left-skewed tree: All left children are visible.

Interview Tips & Best Practices

How to communicate your thought process and address follow-ups in a live technical interview:

  1. State both BFS and DFS solutions to demonstrate versatility.
  2. Explain that DFS uses O(h) call stack memory, which is O(log n) for balanced trees vs O(w) queue space for BFS.
  3. Contrast with Right Side View: Left view visits Left before Right; Right view visits Right before Left.

Quick Comprehension Check

Test your intuitive understanding of the core concept in 30 seconds:

1.In the DFS approach (Root -> Left -> Right), why does condition depth == res.length correctly identify the leftmost visible node?