Left View of a Binary Tree
Problem and examples
| Input Tree | Left View Output | Description |
|---|---|---|
| [1, 2, 3, 4, 5, null, 6] | [1, 2, 4] | Standard binary tree with left and right children; leftmost node at each level forms the left view |
| [1] | [1] | Single node tree; the root is the only node and hence the left view |
| [] | [] | Empty tree; no nodes result in an empty left view |
| [1, 2, null, 3, null, null, null, 4] | [1, 2, 3, 4] | Left-skewed tree; each level has only one leftmost node |
| [1, null, 2, null, null, null, 3] | [1, 2, 3] | Right-skewed tree; the first node at each level still defines the left view |
| [10, 5, 15, 3, 7, null, 18] | [10, 5, 3] | Binary search tree; leftmost visible node from each level contributes to the left view |
Explore Left View of a Binary Tree
Load an example or enter your own input. Use the player controls to follow each change.
Understanding the Problem
The Left View of a Binary Tree refers to the set of nodes visible when the tree is viewed from the left side. At each level of the tree, the leftmost node is considered part of the left view.
To extract this view, we need to explore the tree level by level (using Breadth First Search). At each level, the first node we encounter from left to right is the one visible from the left side.
Step-by-Step Solution with Example
step 1: Visualize the tree
Let's take a sample binary tree:
1
/ 2 3
/ 4 5 6
When viewed from the left side, we see: 1 → 2 → 4
step 2: Use Level Order Traversal
We perform a BFS traversal using a queue. At each level, we process all nodes, and the first node we encounter is added to the left view list.
step 3: Initialize the queue
Start with the root node in the queue. We'll also track the level size to identify the first node at each level.
step 4: Traverse each level
For each level:
- Record the first node we dequeue (this is the leftmost for the level).
- Enqueue its left and right children, if they exist.
step 5: Build the result
Collect the first node from each level and add it to the result list representing the left view.
step 6: Output the final view
For the example above, the result would be: [1, 2, 4]
Edge Cases
Case 1: Left-Skewed Tree
If the tree only has left children like [10, 20, 30], all nodes are visible from the left. Output: [10, 20, 30]
Case 2: Right-Skewed Tree
Even when all nodes are on the right side like [7, null, 8, null, 9], each level still has only one node, so all nodes are visible. Output: [7, 8, 9]
Case 3: Tree with Missing Left Children
In some levels, the left child might be missing but the right child exists. The algorithm should still pick the first node seen at that level, regardless of being a left or right child.
Case 4: Empty Tree
If the tree is empty (null root), the output should be an empty list: []
Finally
To summarize, solving the Left View of a Binary Tree involves understanding that we need the first node seen at every level during a BFS traversal. By using a queue and processing level by level, we can handle any shape of tree—including skewed, sparse, or empty trees. This approach is efficient and beginner-friendly.
- If the binary tree is empty, return an empty list.
- Initialize a queue and add the root node.
- While the queue is not empty, determine the number of nodes at the current level.
- For each node at the current level, dequeue the node. If it is the first node in this level, record its value.
- Enqueue the left and right children of the node, if they exist.
- Repeat until all levels are processed. The recorded values form the left view of the tree.
Implementation and efficiency
C implementation
#include <stdio.h>
#include <stdlib.h>
struct TreeNode {
int val;
struct TreeNode *left, *right;
};
struct TreeNode* createNode(int val) {
struct TreeNode* node = (struct TreeNode*)malloc(sizeof(struct TreeNode));
node->val = val;
node->left = node->right = NULL;
return node;
}
int* leftView(struct TreeNode* root, int* returnSize) {
if (!root) {
*returnSize = 0;
return NULL;
}
struct TreeNode** queue = malloc(100 * sizeof(struct TreeNode*));
int* result = malloc(100 * sizeof(int));
int front = 0, rear = 0, resIndex = 0;
queue[rear++] = root;
while (front < rear) {
int levelSize = rear - front;
for (int i = 0; i < levelSize; i++) {
struct TreeNode* node = queue[front++];
if (i == 0) result[resIndex++] = node->val;
if (node->left) queue[rear++] = node->left;
if (node->right) queue[rear++] = node->right;
}
}
*returnSize = resIndex;
free(queue);
return result;
}
int main() {
struct TreeNode* root = createNode(1);
root->left = createNode(2);
root->right = createNode(3);
root->left->left = createNode(4);
root->left->right = createNode(5);
root->right->right = createNode(6);
int returnSize;
int* res = leftView(root, &returnSize);
printf("Left View: ");
for (int i = 0; i < returnSize; i++) {
printf("%d ", res[i]);
}
printf("\n");
free(res);
return 0;
}C++ implementation
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
struct TreeNode {
int val;
TreeNode *left, *right;
TreeNode(int x): val(x), left(nullptr), right(nullptr) {}
};
vector<int> leftView(TreeNode* root) {
vector<int> result;
if (!root) return result;
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
int levelSize = q.size();
for (int i = 0; i < levelSize; i++) {
TreeNode* node = q.front(); q.pop();
if (i == 0) result.push_back(node->val);
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
}
return result;
}
int main() {
TreeNode* root = new TreeNode(1);
root->left = new TreeNode(2);
root->right = new TreeNode(3);
root->left->left = new TreeNode(4);
root->left->right = new TreeNode(5);
root->right->right = new TreeNode(6);
vector<int> res = leftView(root);
cout << "Left View: ";
for (int val : res) cout << val << " ";
cout << endl;
return 0;
}Python implementation
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def leftView(root):
if not root:
return []
from collections import deque
queue = deque([root])
result = []
while queue:
level_size = len(queue)
for i in range(level_size):
node = queue.popleft()
if i == 0:
result.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return result
if __name__ == '__main__':
root = TreeNode(1, TreeNode(2, TreeNode(4), TreeNode(5)), TreeNode(3, None, TreeNode(6)))
print("Left View:", leftView(root))Java implementation
import java.util.*;
class TreeNode {
int val;
TreeNode left, right;
TreeNode(int x) { val = x; }
}
public class LeftViewBinaryTree {
public List<Integer> leftView(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 node = queue.poll();
if (i == 0) result.add(node.val);
if (node.left != null) queue.add(node.left);
if (node.right != null) queue.add(node.right);
}
}
return result;
}
public static void main(String[] args) {
TreeNode root = new TreeNode(1);
root.left = new TreeNode(2);
root.right = new TreeNode(3);
root.left.left = new TreeNode(4);
root.left.right = new TreeNode(5);
root.right.right = new TreeNode(6);
LeftViewBinaryTree sol = new LeftViewBinaryTree();
System.out.println("Left View: " + sol.leftView(root));
}
}JavaScript implementation
class TreeNode {
constructor(val, left = null, right = null) {
this.val = val;
this.left = left;
this.right = right;
}
}
function leftView(root) {
if (!root) return [];
const queue = [root];
const result = [];
while (queue.length > 0) {
const levelSize = queue.length;
for (let i = 0; i < levelSize; i++) {
const node = queue.shift();
if (i === 0) result.push(node.val);
if (node.left) queue.push(node.left);
if (node.right) queue.push(node.right);
}
}
return result;
}
const root = new TreeNode(1, new TreeNode(2, new TreeNode(4), new TreeNode(5)), new TreeNode(3, null, new TreeNode(6)));
console.log("Left View:", leftView(root));Go implementation
package main
import (
"fmt"
)
type TreeNode struct {
val int
left *TreeNode
right *TreeNode
}
func createNode(val int) *TreeNode {
return &TreeNode{val: val}
}
func leftView(root *TreeNode) []int {
if root == nil {
return []int{}
}
queue := []*TreeNode{root}
result := []int{}
for len(queue) > 0 {
size := len(queue)
for i := 0; i < size; i++ {
node := queue[0]
queue = queue[1:]
if i == 0 {
result = append(result, node.val)
}
if node.left != nil {
queue = append(queue, node.left)
}
if node.right != nil {
queue = append(queue, node.right)
}
}
}
return result
}
func main() {
root := createNode(1)
root.left = createNode(2)
root.right = createNode(3)
root.left.left = createNode(4)
root.left.right = createNode(5)
root.right.right = createNode(6)
fmt.Println("Left View:", leftView(root))
}Rust implementation
use std::collections::VecDeque;
#[derive(Debug)]
struct TreeNode {
val: i32,
left: Option<Box<TreeNode>>,
right: Option<Box<TreeNode>>,
}
impl TreeNode {
fn new(val: i32) -> Self {
TreeNode { val, left: None, right: None }
}
}
fn left_view(root: Option<Box<TreeNode>>) -> Vec<i32> {
let mut result = Vec::new();
if root.is_none() { return result; }
let mut queue = VecDeque::new();
queue.push_back(root);
while !queue.is_empty() {
let level_size = queue.len();
for i in 0..level_size {
if let Some(Some(node)) = queue.pop_front() {
if i == 0 {
result.push(node.val);
}
queue.push_back(node.left);
queue.push_back(node.right);
}
}
}
result
}
fn main() {
let root = Some(Box::new(TreeNode {
val: 1,
left: Some(Box::new(TreeNode {
val: 2,
left: Some(Box::new(TreeNode::new(4))),
right: Some(Box::new(TreeNode::new(5))),
})),
right: Some(Box::new(TreeNode {
val: 3,
left: None,
right: Some(Box::new(TreeNode::new(6))),
})),
}));
println!("Left View: {:?}", left_view(root));
}Kotlin implementation
import java.util.*
data class TreeNode(val val: Int, var left: TreeNode? = null, var right: TreeNode? = null)
fun leftView(root: TreeNode?): List<Int> {
val result = mutableListOf<Int>()
if (root == null) return result
val queue: Queue<TreeNode> = LinkedList()
queue.add(root)
while (queue.isNotEmpty()) {
val size = queue.size
for (i in 0 until size) {
val node = queue.poll()
if (i == 0) result.add(node.val)
node.left?.let { queue.add(it) }
node.right?.let { queue.add(it) }
}
}
return result
}
fun main() {
val root = TreeNode(1)
root.left = TreeNode(2, TreeNode(4), TreeNode(5))
root.right = TreeNode(3, null, TreeNode(6))
println("Left View: ${leftView(root)}")
}TypeScript implementation
class TreeNode {
val: number;
left: TreeNode | null;
right: TreeNode | null;
constructor(val: number, left: TreeNode | null = null, right: TreeNode | null = null) {
this.val = val;
this.left = left;
this.right = right;
}
}
function leftView(root: TreeNode | null): number[] {
if (!root) return [];
const result: number[] = [];
const queue: TreeNode[] = [root];
while (queue.length > 0) {
const levelSize = queue.length;
for (let i = 0; i < levelSize; i++) {
const node = queue.shift()!;
if (i === 0) result.push(node.val);
if (node.left) queue.push(node.left);
if (node.right) queue.push(node.right);
}
}
return result;
}
const root = new TreeNode(1,
new TreeNode(2, new TreeNode(4), new TreeNode(5)),
new TreeNode(3, null, new TreeNode(6))
);
console.log("Left View:", leftView(root));