Talentd
FleetCode
Make and follow sheets.Sign in

Binary Tree Level Order Traversal solution and explanation

MediumBinary TreeBreadth-First SearchTree6 min read73.5% acceptanceUpdated 9 Apr 2026
Binary Tree Level Order Traversal - BFS - Leetcode 102NeetCode · 9:36 · 286K viewsWatch on YouTube
9 more videos on this problem
  1. Binary Tree Level Order Traversal - BFS - Leetcode 102NeetCode · 9:36 · 286K views
  2. Binary Tree Level Order Traversal | Live Coding with Explanation | Leetcode - 102Algorithms Made Easy · 11:34 · 16K views
  3. Binary Tree Level Order Traversal (BFS) - Leetcode 102 - Trees (Python)Greg Hogg · 9:49 · 14K views
  4. LeetCode 102. Binary Tree Level Order Traversal - Interview Prep Ep 70Fisher Coder · 8:58 · 7K views
  5. BINARY TREE LEVEL ORDER TRAVERSAL | PYTHON SOLUTION | LEETCODE # 102Cracking FAANG · 12:03 · 3K views
  6. Binary Tree Level Order Traversal - LeetCode 102 - JavaScriptAlgoJS · 5:06 · 2K views
  7. Binary Tree Level Order Traversal - LeetCode 102 - LeetCode SolutionsOne Code Man · 3:52 · 2K views
  8. 102. Binary Tree Level Order Traversal Java SolutionCode with Carter · 8:54 · 1K views
  9. Binary Tree Level Order | LeetCode 102 (Medium)Destination FAANG · 12:14 · 709 views
  10. LeetCode Problem 102: Binary Tree Level Order Traversal in Java - FAANG Coding Interview - Blind 75KeyStrokes · 11:52 · 693 views

The problem

Given the root of a binary tree, return the level order traversal of its nodes' values. (i.e., from left to right, level by level).

Example 1:

Input: root = [3,9,20,null,null,15,7]
Output: [[3],[9,20],[15,7]]

Example 2:

Input: root = [1]
Output: [[1]]

Example 3:

Input: root = []
Output: []

Constraints:

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

Approach overview

Problem Overview: Given the root of a binary tree, return the node values level by level from left to right. Each level should appear as a separate list in the final result.

Approach 1: Breadth-First Search Using Queue (O(n) time, O(w) space)

This problem naturally fits Breadth-First Search. Use a queue to process nodes level by level. Start by pushing the root node into the queue. For each iteration, record the current queue size because it represents the number of nodes at that level. Dequeue exactly that many nodes, append their values to the current level list, and push their left and right children into the queue. Continue until the queue is empty. Every node is visited exactly once, so the time complexity is O(n). The queue can hold up to the width of the tree, giving O(w) auxiliary space in the worst case.

This approach mirrors the conceptual definition of level order traversal. Because nodes are processed in the same order they appear by depth, the implementation stays simple and predictable. When working with tree traversal problems that require grouping nodes by depth, BFS is usually the first algorithm to consider.

Approach 2: Depth-First Search with Precomputed Levels (O(n) time, O(h) space)

A binary tree can also be traversed using DFS while tracking the current depth. During recursion, pass the level index as a parameter. If the result list does not yet contain a list for that depth, create one. Then append the current node's value to result[level]. Recursively process the left child and then the right child with level + 1.

This method still visits each node exactly once, so the runtime remains O(n). The recursion stack grows to the tree height h, giving O(h) auxiliary space (excluding the output). DFS is useful when the problem already requires recursive traversal or when you want tighter control over recursion logic. The tradeoff is that level grouping must be handled manually using the depth index.

Recommended for interviews: The BFS queue approach is what interviewers usually expect first. Level order traversal is essentially BFS applied to a tree, so recognizing that mapping quickly demonstrates algorithmic intuition. Showing the DFS-with-level-index variant afterward demonstrates deeper understanding of tree traversal patterns and flexibility in implementation.

Approach 1: Breadth-First Search Using Queue

This approach utilizes a queue to perform a Breadth-First Search (BFS) on the binary tree. Starting from the root, traverse each level of the tree and store values of nodes in separate lists for each level. By using a queue, we can efficiently keep track of nodes at the current level and their respective children for the next level.

from collections import deque

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

def levelOrder(root):
    if not root:
        return []
    result = []
    queue = deque([root])
    while queue:
        level_size = len(queue)
        level_nodes = []
        for _ in range(level_size):
            node = queue.popleft()
            level_nodes.append(node.val)
            if node.left:
                queue.append(node.left)
            if node.right:
                queue.append(node.right)
        result.append(level_nodes)
    return result
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode() {}
    TreeNode(int val) { this.val = val; }
    TreeNode(int val, TreeNode left, TreeNode right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

public class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> levels = new ArrayList<>();
        if (root == null) return levels;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()) {
            int levelSize = queue.size();
            List<Integer> level = new ArrayList<>();
            for (int i = 0; i < levelSize; i++) {
                TreeNode node = queue.poll();
                level.add(node.val);
                if (node.left != null) queue.add(node.left);
                if (node.right != null) queue.add(node.right);
            }
            levels.add(level);
        }
        return levels;
    }
}
function TreeNode(val, left, right) {
    this.val = (val===undefined ? 0 : val);
    this.left = (left===undefined ? null : left);
    this.right = (right===undefined ? null : right);
}

function levelOrder(root) {
    if (!root) return [];
    const result = [];
    const queue = [root];
    while (queue.length > 0) {
        const levelSize = queue.length;
        const levelNodes = [];
        for (let i = 0; i < levelSize; i++) {
            const node = queue.shift();
            levelNodes.push(node.val);
            if (node.left) queue.push(node.left);
            if (node.right) queue.push(node.right);
        }
        result.push(levelNodes);
    }
    return result;
}

We use a deque from the collections module to easily append and pop nodes from the queue. Starting with the root node if it is not null, we add it to the queue. For each level, determine the number of nodes at that level (i.e., the size of the queue), then iterate over them, adding each node's children to the queue for the next level. Collect and return the node values in a nested list representing each level.

Complexity

Time Complexity: O(n), where n is the number of nodes in the tree because each node is visited once.
Space Complexity: O(n), as we store all nodes at each level in the queue.

Try this approach in the editor

Approach 2: Depth-First Search (DFS) with Precomputed Levels

This approach involves using a Depth-First Search (DFS) where we pass along the current level during the recursive calls. By keeping track of the current depth, we can directly add node values to their appropriate level in our result list, creating new levels in our result list as needed.

#include <vector>
using namespace std;

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

void dfs(TreeNode* node, int level, vector<vector<int>>& levels) {
    if (!node) return;
    if (level == levels.size())
        levels.push_back(vector<int>());
    levels[level].push_back(node->val);
    dfs(node->left, level + 1, levels);
    dfs(node->right, level + 1, levels);
}

vector<vector<int>> levelOrder(TreeNode* root) {
    vector<vector<int>> levels;
    dfs(root, 0, levels);
    return levels;
}
#include <stdio.h>
#include <stdlib.h>

struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
};

void dfs(struct TreeNode* node, int level, int** result, int* returnSize, int** resultColSizes) {
    if (!node) return;
    if (level >= *returnSize) {
        *returnSize += 1;
        result[*returnSize - 1] = (int*)malloc(2000 * sizeof(int));
        (*resultColSizes)[*returnSize - 1] = 0;
    }
    result[level][(*resultColSizes)[level]] = node->val;
    (*resultColSizes)[level] += 1;
    dfs(node->left, level + 1, result, returnSize, resultColSizes);
    dfs(node->right, level + 1, result, returnSize, resultColSizes);
}

int** levelOrder(struct TreeNode* root, int* returnSize, int** resultColSizes) {
    *returnSize = 0;
    int** result = (int**)malloc(2000 * sizeof(int*));
    *resultColSizes = (int*)malloc(2000 * sizeof(int));
    dfs(root, 0, result, returnSize, resultColSizes);
    return result;
}
using System;
using System.Collections.Generic;

public class TreeNode {
    public int val;
    public TreeNode left;
    public TreeNode right;
    public TreeNode(int x) { val = x; }
}

public class Solution {
    public IList<IList<int>> LevelOrder(TreeNode root) {
        var levels = new List<IList<int>>();
        DFS(root, 0, levels);
        return levels;
    }
    
    private void DFS(TreeNode node, int level, List<IList<int>> levels) {
        if (node == null) return;
        if (level == levels.Count) 
            levels.Add(new List<int>());
        levels[level].Add(node.val);
        DFS(node.left, level + 1, levels);
        DFS(node.right, level + 1, levels);
    }
}

Invoke the DFS function recursively by starting at the root node. We use a vector of vectors to represent levels during traversal. For each visited node, determine the current level size and append values to their respective level container, expanding the container list when necessary. Recurse into children while maintaining depth count to achieve the level order.

Complexity

Time Complexity: O(n), where n is the total number of nodes.
Space Complexity: O(h) on the call stack, plus O(n) for storing the result, where h is the height of the tree.

Try this approach in the editor

Approach 3: BFS

We can use the BFS method to solve this problem. First, enqueue the root node, then continuously perform the following operations until the queue is empty:

  • Traverse all nodes in the current queue, store their values in a temporary array t, and then enqueue their child nodes.
  • Store the temporary array t in the answer array.

Finally, return the answer array.

The time complexity is O(n), and the space complexity is O(n). Here, n is the number of nodes in the binary tree.

/**
 * Definition for a binary tree node.
 * class TreeNode {
 *     val: number
 *     left: TreeNode | null
 *     right: TreeNode | null
 *     constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
 *         this.val = (val===undefined ? 0 : val)
 *         this.left = (left===undefined ? null : left)
 *         this.right = (right===undefined ? null : right)
 *     }
 * }
 */

function levelOrder(root: TreeNode | null): number[][] {
    const ans: number[][] = [];
    if (!root) {
        return ans;
    }
    const q: TreeNode[] = [root];
    while (q.length) {
        const t: number[] = [];
        const qq: TreeNode[] = [];
        for (const { val, left, right } of q) {
            t.push(val);
            left && qq.push(left);
            right && qq.push(right);
        }
        ans.push(t);
        q.splice(0, q.length, ...qq);
    }
    return ans;
}
/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func levelOrder(root *TreeNode) (ans [][]int) {
	if root == nil {
		return
	}
	q := []*TreeNode{root}
	for len(q) > 0 {
		t := []int{}
		for n := len(q); n > 0; n-- {
			node := q[0]
			q = q[1:]
			t = append(t, node.Val)
			if node.Left != nil {
				q = append(q, node.Left)
			}
			if node.Right != nil {
				q = append(q, node.Right)
			}
		}
		ans = append(ans, t)
	}
	return
}
// Definition for a binary tree node.
// #[derive(Debug, PartialEq, Eq)]
// pub struct TreeNode {
//   pub val: i32,
//   pub left: Option<Rc<RefCell<TreeNode>>>,
//   pub right: Option<Rc<RefCell<TreeNode>>>,
// }
//
// impl TreeNode {
//   #[inline]
//   pub fn new(val: i32) -> Self {
//     TreeNode {
//       val,
//       left: None,
//       right: None
//     }
//   }
// }
use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::Rc;
impl Solution {
    pub fn level_order(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<Vec<i32>> {
        let mut ans = Vec::new();
        if let Some(root_node) = root {
            let mut q = VecDeque::new();
            q.push_back(root_node);
            while !q.is_empty() {
                let mut t = Vec::new();
                for _ in 0..q.len() {
                    if let Some(node) = q.pop_front() {
                        let node_ref = node.borrow();
                        t.push(node_ref.val);
                        if let Some(ref left) = node_ref.left {
                            q.push_back(Rc::clone(left));
                        }
                        if let Some(ref right) = node_ref.right {
                            q.push_back(Rc::clone(right));
                        }
                    }
                }
                ans.push(t);
            }
        }
        ans
    }
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
Breadth-First Search Using Queue

Time Complexity: O(n), where n is the number of nodes in the tree because each node is visited once.
Space Complexity: O(n), as we store all nodes at each level in the queue.

Depth-First Search (DFS) with Precomputed Levels

Time Complexity: O(n), where n is the total number of nodes.
Space Complexity: O(h) on the call stack, plus O(n) for storing the result, where h is the height of the tree.

BFS–

Complexity analysis

ApproachTimeSpaceWhen to Use
Breadth-First Search Using QueueO(n)O(w)Standard level order traversal; easiest and most intuitive solution
Depth-First Search with Level IndexO(n)O(h)Useful when implementing recursive tree traversals or when DFS structure is preferred

Frequently asked questions

Is Binary Tree Level Order Traversal easy or hard?

Binary Tree Level Order Traversal is generally considered a medium-level problem. The core logic is straightforward BFS, but candidates must correctly manage level boundaries and queue operations during traversal.

Binary Tree Level Order Traversal Python/Java solution

In Python, collections.deque is typically used to implement the BFS queue efficiently. In Java, developers commonly use LinkedList or ArrayDeque as the queue implementation while processing nodes level by level.

How to solve Binary Tree Level Order Traversal in O(n)?

Use a queue to perform a breadth-first traversal. Push the root into the queue, process nodes level by level by iterating through the current queue size, and enqueue left and right children. Since each node is processed once, the overall complexity is O(n).

What is the best approach for Binary Tree Level Order Traversal?

Breadth-First Search (BFS) using a queue is the most common approach. Nodes are processed level by level by pushing children into a queue while iterating through the current level size. This guarantees each node is visited once with O(n) time complexity.

Is Binary Tree Level Order Traversal asked at Google/Amazon/Meta?

Binary tree traversal problems, including level order traversal, appear frequently in interviews at companies like Google, Amazon, and Meta. They test understanding of BFS, queue usage, and basic tree data structure operations.

What data structure is used in Binary Tree Level Order Traversal?

A queue is the primary data structure used for the BFS approach. It maintains the processing order of nodes so that nodes at the same depth are visited together before moving to the next level.

What is the time complexity of Binary Tree Level Order Traversal?

The time complexity is O(n) because each node in the binary tree is visited exactly once. The auxiliary space is O(w) for BFS where w is the maximum width of the tree, or O(h) for a DFS recursion stack where h is the tree height.

Comments

Now write it yourselfClose this page and solve Binary Tree Level Order Traversal in the editor, without looking.
Practise Binary Tree Level Order Traversal