
Problem Statement
Given a binary tree's root node, the task is to perform a level order traversal on it. This traversal involves visiting all the nodes at the current depth level from left to right before moving to the next level in the tree.
Examples
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 and Intuition
The level order traversal of a binary tree, also known as breadth-first traversal, requires the traversal of nodes level by level, progressing from left to right at each level. Here's a step-by-step approach and the intuition behind it:
Initial Check:
- Check if the root is null. If it is, return an empty list because there are no nodes to traverse.
Queue Utilization:
- Utilize a queue to keep track of nodes at the current level. Initially, add the root to this queue.
Traversal:
- While the queue is not empty:
- Determine the number of nodes at the current level (size of the queue).
- For each node in the current level:
- Add it to a temporary list (current level).
- Enqueue its children (left then right) if they exist.
- After processing all nodes at the current level, add the temporary list to the final result list.
- While the queue is not empty:
Result Compilation:
- Continue the process until the queue is empty and all levels are processed.
- Return the compiled list of levels.
This method ensures that all nodes on the same level are processed together, and each level is handled before moving onto the next. The constraints given allow the method to handle trees of size up to 2000 nodes comfortably, with values ranging from -1000 to 1000.
Solutions
- C++
- Java
- C
- JavaScript
- Python
class Solution {
public:
vector<vector<int>> traverseLevels(TreeNode* root) {
vector<vector<int>> result;
if (!root) return result;
deque<TreeNode*> deque;
deque.push_back(root);
int currentLevel = 0;
while (!deque.empty()) {
result.push_back(vector<int>());
int nodesAtLevel = deque.size();
for (int i = 0; i < nodesAtLevel; ++i) {
TreeNode* currentNode = deque.front();
deque.pop_front();
result[currentLevel].push_back(currentNode->val);
if (currentNode->left) deque.push_back(currentNode->left);
if (currentNode->right) deque.push_back(currentNode->right);
}
currentLevel++;
}
return result;
}
};
The provided C++ code defines a method traverseLevels
that performs a level-order traversal on a binary tree. The method returns a two-dimensional vector containing the values of the nodes at each level of the binary tree:
- The function starts by checking if the root is
nullptr
, returning an empty result if true. - It then initializes a
deque
to store the nodes of the tree and a result vector of vector of integers to keep the values. - The root node gets added to the deque initially.
- A
while
loop runs as long as the deque is not empty. Inside the loop:- A new vector is added to
result
to store the values of nodes at the current level. - The number of nodes at the current level is determined using the size of the deque.
- A
for
loop runs for the number of nodes at that level:- It pops nodes from the front of the deque.
- The values of these nodes are added to the current level's vector in
result
. - If the
left
orright
child of the node exists, they are added to the back of the deque to be processed in the coming iterations.
- The
currentLevel
counter is incremented after processing each level.
- A new vector is added to
- The function ultimately returns the
result
, which contains the level order traversal of the binary tree.
This C++ implementation efficiently maps out the nodes of a binary tree by levels using a deque for optimal access and insertion operations.
class Solution {
public List<List<Integer>> traverseByLevels(TreeNode root) {
List<List<Integer>> allLevels = new ArrayList<>();
if (root == null) return allLevels;
Queue<TreeNode> nodeQueue = new LinkedList<>();
nodeQueue.add(root);
int currentLevel = 0;
while (!nodeQueue.isEmpty()) {
allLevels.add(new ArrayList<Integer>());
int levelSize = nodeQueue.size();
for (int i = 0; i < levelSize; ++i) {
TreeNode current = nodeQueue.poll();
allLevels.get(currentLevel).add(current.val);
if (current.left != null) nodeQueue.add(current.left);
if (current.right != null) nodeQueue.add(current.right);
}
currentLevel++;
}
return allLevels;
}
}
The provided Java method traverseByLevels
performs a level order traversal on a binary tree. This method returns a List<List<Integer>>
, where each nested list contains the values of the tree nodes at each depth level of the tree.
Follow these steps to understand how the solution works:
- Initialize an empty list
allLevels
to store the values of nodes at each level. - Check if the root node is null. If so, return the empty
allLevels
list immediately as there are no nodes to process. - Use a
Queue<TreeNode>
to help with the level order traversal. Begin by enqueueing the root node. - Declare a variable
currentLevel
to keep track of the tree depth during traversal. - Use a while loop to process nodes as long as there are any left in the queue.
- Add a new list into
allLevels
to prepare for storing node values of the current level. - Calculate the number of nodes at the current level with
levelSize
which is equal to the number of nodes in the queue at the start of the loop. - Loop over each node at the current level:
- Dequeue the node from the front of the queue.
- Add the node's value to the current level list inside
allLevels
. - Enqueue the child nodes (left first, then right) of the current node if they are not null.
- Increment
currentLevel
to move to the next level in subsequent iterations.
- Add a new list into
- Once the queue is empty, return the
allLevels
which now contains all node values organized level by level.
This method efficiently traverses each node once and processes all nodes level by level using a queue, adhering to the standard breadth-first searching technique in tree data structures.
int** bfsTraversal(struct TreeNode* root, int* returnSize, int** returnColumnSizes) {
*returnSize = 0;
if (!root) return NULL;
typedef struct Element {
void* content;
struct Element* next;
} Element;
typedef struct SimpleQueue {
Element* first;
Element* last;
} SimpleQueue;
SimpleQueue* initializeQueue() {
SimpleQueue* q = malloc(sizeof(SimpleQueue));
q->first = q->last = NULL;
return q;
}
void enqueue(SimpleQueue* q, void* content) {
Element* elem = malloc(sizeof(Element));
elem->content = content;
elem->next = NULL;
if (q->first == NULL) {
q->first = q->last = elem;
} else {
q->last = q->last->next = elem;
}
}
void* dequeue(SimpleQueue* q) {
if (!q->first) return NULL;
Element* tmp = q->first;
void* content = tmp->content;
q->first = q->first->next;
if (q->first == NULL) q->last = NULL;
free(tmp);
return content;
}
size_t queueSize(SimpleQueue* q) {
size_t count = 0;
for (Element* elem = q->first; elem != NULL; elem = elem->next) {
count++;
}
return count;
}
int queueIsEmpty(SimpleQueue* q) {
return q->first == NULL;
}
SimpleQueue* queue = initializeQueue();
enqueue(queue, root);
int** treeLevels = malloc(sizeof(int*) * 2000);
*returnColumnSizes = (int*)malloc(sizeof(int) * 2000);
while (!queueIsEmpty(queue)) {
int nodesAtLevel = queueSize(queue);
treeLevels[*returnSize] = malloc(sizeof(int) * nodesAtLevel);
(*returnColumnSizes)[*returnSize] = nodesAtLevel;
for (int i = 0; i < nodesAtLevel; i++) {
struct TreeNode* node = dequeue(queue);
treeLevels[*returnSize][i] = node->val;
if (node->left) enqueue(queue, node->left);
if (node->right) enqueue(queue, node->right);
}
(*returnSize)++;
}
return treeLevels;
}
The provided C code performs a breadth-first search (BFS) on a binary tree to return the values of the nodes level by level. This approach uses a custom queue structure to manage the nodes during traversal. Here's how it works:
- Initializes a
returnSize
to keep track of how many levels in the tree have been processed. - Checks if the input
root
is NULL. If so, returns NULL. - Defines a
SimpleQueue
andElement
to create a basic queue structure capable of handling generic content. - Implements helper functions for the queue:
initializeQueue
to create a new queue,enqueue
anddequeue
to add and remove elements,queueSize
to determine the current size of the queue, andqueueIsEmpty
to check if the queue is empty. - Begins the BFS:
- Initializes the queue and enqueues the root node.
- Uses an array
treeLevels
to store the node values for each level. - Dynamically allocates an array
returnColumnSizes
to store the number of nodes at each level. - Processes each level of the tree by dequeueing all nodes at the current level, storing their values, and enqueueing their children.
- The level processing continues until the queue is empty.
- The function finally returns
treeLevels
, an array of pointers where each pointer points to an array containing the values of the nodes at that level.
This solution efficiently captures the hierarchical structure of a binary tree using a level order traversal, which is particularly useful for tasks that require knowledge of the tree structure beyond simple depth-first traversals. The use of dynamic memory management and custom data structures ensures flexibility and thorough traversal of the tree.
var bfsTraversal = function (rootNode) {
var result = [];
if (!rootNode) return result;
var nodeQueue = [rootNode];
var currentLevel = 0;
while (nodeQueue.length > 0) {
result.push([]);
var levelSize = nodeQueue.length;
for (var i = 0; i < levelSize; i++) {
var currentNode = nodeQueue.shift();
result[currentLevel].push(currentNode.val);
if (currentNode.left) nodeQueue.push(currentNode.left);
if (currentNode.right) nodeQueue.push(currentNode.right);
}
currentLevel++;
}
return result;
};
The provided JavaScript function, bfsTraversal
, implements a breadth-first search (BFS) strategy to perform a level order traversal on a binary tree. This is a commonly used technique to visit all the nodes of a binary tree level by level from left to right. Here's a breakdown on how this function works:
- Initialize an empty array
result
to store the nodes at each level. - If the root node is null, return the empty result array immediately; this handles the edge case where the binary tree is empty.
- Use an array
nodeQueue
to keep track of nodes to visit, starting with the root node. - The variable
currentLevel
is used to track the depth of traversal into the binary tree.
The main computational work happens inside a while loop, which continues as long as there are nodes to process in nodeQueue
:
- An empty sublist is added to
result
for the current level. - The current level's size is determined by
nodeQueue.length
, which indicates how many nodes need to be processed at this level. - A for loop iterates over each node in the current level:
- The node at the front of the queue is removed and processed.
- The value of the current node is added to the corresponding level list in
result
. - If the current node has a left child, it is added to
nodeQueue
to be processed in the next level. Similarly, if there's a right child, it is also added.
- Increment
currentLevel
to move to the next level in the binary tree.
The function concludes by returning the result
, which contains lists of node values at each level of the binary tree.
This code efficiently handles different scenarios, including trees of varying sizes and shapes, by adapting to the breadth and depth dynamically. Additionally, the straightforward use of list operations for queues makes the code easy to read and understand, utilizing JavaScript's native array functionalities.
Keep this approach in mind when you need to handle hierarchical data structures like trees, as BFS is often a suitable choice for evenly exploring each level. This function can be seamlessly integrated into larger applications or used in standalone form to process tree-based data efficiently.
from collections import deque
class Solution:
def traverseBinaryTree(self, root: TreeNode) -> List[List[int]]:
result = []
if not root:
return result
current_level = 0
queue = deque([root])
while queue:
result.append([])
num_nodes = len(queue)
for _ in range(num_nodes):
current_node = queue.popleft()
result[current_level].append(current_node.val)
if current_node.left:
queue.append(current_node.left)
if current_node.right:
queue.append(current_node.right)
current_level += 1
return result
The Python code provided performs a level order traversal on a binary tree using the deque
from the collections
module for efficient queue operations. Here's an overview of the solution's implementation:
- Initialize an empty list,
result
, to store the traversal results. - Check if the root is
None
; if true, return an empty list. - Initialize a
current_level
variable to track the current tree level starting from 0. - Create a
queue
and enqueue the root node to start the traversal. - Use a
while
loop to process nodes while there are nodes in the queue:- Begin each new level by appending an empty list to
result
. - Determine the number of nodes,
num_nodes
, at the current tree level. - Iterate through these nodes using a for loop:
- Dequeue a node from the front of the
queue
. - Append its value to the list corresponding to
current_level
. - Enqueue the left and right children to the
queue
, if they exist.
- Dequeue a node from the front of the
- Increment
current_level
to move to the next level.
- Begin each new level by appending an empty list to
- Finally, return the
result
, which contains the values of the tree nodes organized by their levels.
This approach ensures that each level of the tree is processed separately and that nodes at the same level are processed together in order, resulting in a grouped list of values by tree depth. The use of a deque for the queue minimizes the time complexity associated with frequently adding and removing elements from the queue.
No comments yet.