
Problem Statement
In this task, we are dealing with a binary tree. The goal is to perform a traversal that records the values of nodes level by level, starting from the leaf nodes and moving up to the root. This order of traversal is known as a bottom-up level order traversal. Each level's node values should be listed from left to right, and the levels themselves should be listed from bottom (leaf) to top (root). The challenge involves both understanding the structure of the given binary tree and implementing an algorithm to traverse and record values in the required order.
Examples
Example 1
Input:
root = [3,9,20,null,null,15,7]
Output:
[[15,7],[9,20],[3]]
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
To tackle this problem, the ideal way is to use Breadth-First Search (BFS) due to its nature of exploring nodes level by level. However, since we need a bottom-up level order, we will modify our approach to reverse the typical top-down level order result.
- First, check if the root is null. If so, return an empty list as there are no nodes to traverse.
- Initialize a queue to help with BFS traversal. This queue will store nodes along with their corresponding tree level.
- Use a list (or deque for efficiency) to hold the final results and a temporary list for nodes at the current level.
- As you dequeue nodes, enqueue their child nodes (left first, then right).
- Once an entire level is processed, append the list of node values for that level to the beginning of your result list. This will ensure that the bottom-most level ends up at the end of the result list, effectively reversing the order without additional operations.
- Continue the BFS until you've processed all levels of the tree.
- Return the list containing the reversed levels.
Some key points to note:
- The input tree may have 0 nodes, in which case we immediately return an empty list.
- Node values can range from -1000 to 1000, which doesn't affect the traversal or recording mechanism but is essential to ensure the traversal algorithm handles the range correctly.
- The tree can have a maximum of 2000 nodes, meaning the BFS will perform efficiently within this limit.
Solutions
- C++
- Java
- C
- JavaScript
- Python
class Solution {
public:
vector<vector<int>> bottomUpLevelOrder(TreeNode* root) {
vector<vector<int>> result;
if (!root) return result;
deque<TreeNode*> queue_next;
queue_next.push_back(root);
while (!queue_next.empty()) {
deque<TreeNode*> queue_current = queue_next;
queue_next.clear();
result.push_back(vector<int>());
for (TreeNode* node : queue_current) {
result.back().push_back(node->val);
if (node->left) queue_next.push_back(node->left);
if (node->right) queue_next.push_back(node->right);
}
}
reverse(result.begin(), result.end());
return result;
}
};
The given C++ code implements a solution for the problem of performing a bottom-up level order traversal on a binary tree. The function bottomUpLevelOrder
provides a structured way to traverse the tree starting from the root node towards the leaves, and then collecting the values level by level from bottom to top.
- The
TreeNode
structure is referenced, and it is assumed that each node hasval
,left
, andright
attributes. - A
vector
ofvector<int>>
namedresult
is used to store the integers at each level of the tree. - A
deque
(double-ended queue) namedqueue_next
helps in maintaining the current level's nodes while traversing the tree using breadth-first search (BFS). - The function starts by checking if the
root
isnullptr
, immediately returning an emptyresult
if true. - If the
root
is notnullptr
, the root node is added toqueue_next
. - A while loop is used to process each tree level until
queue_next
is empty.- A
queue_current
deque copies all nodes fromqueue_next
andqueue_next
is then cleared. - For every node in
queue_current
:- The node's value is appended to the current last vector in
result
. - If the node has a left child, it is added to
queue_next
. - If the node has a right child, it is also added to
queue_next
.
- The node's value is appended to the current last vector in
- A
- After processing all levels in direct top-to-bottom order, the vectors inside
result
are reversed to meet the bottom-up requirement using thereverse
function, thus rearranging them from bottom level to top level. - Finally,
result
is returned, now correctly representing the level order traversal from the bottom-up.
This implementation ensures that the tree values are collected and organized efficiently while respecting the bottom-up traversal constraint.
class Solution {
public List<List<Integer>> bottomUpLevelOrder(TreeNode root) {
List<List<Integer>> result = new ArrayList<>();
if (root == null) return result;
ArrayDeque<TreeNode> queueNext = new ArrayDeque() {{ offer(root); }};
ArrayDeque<TreeNode> queueCurrent = new ArrayDeque();
while (!queueNext.isEmpty()) {
queueCurrent = queueNext.clone();
queueNext.clear();
result.add(new ArrayList<Integer>());
for (TreeNode node : queueCurrent) {
result.get(result.size() - 1).add(node.val);
if (node.left != null) queueNext.offer(node.left);
if (node.right != null) queueNext.offer(node.right);
}
}
Collections.reverse(result);
return result;
}
}
Implement bottom-up level order traversal of a binary tree in Java, retrieving values from the tree's nodes in reverse level order—starting from the bottommost nodes to the root. Follow these steps:
- Begin by initializing a result list (
result
) to store the values of each level. - Check if the tree root is
null
. If true, immediately return the empty result list, since an empty tree has no levels to traverse. - Use two
ArrayDeque<TreeNode>
instances,queueNext
to track nodes being accessed in the next level andqueueCurrent
to hold nodes being accessed in the current level. StartqueueNext
with the tree root. - While
queueNext
is not empty:- Clone
queueNext
toqueueCurrent
and clearqueueNext
. - Add a new list to
result
to store the current level nodes’ values. - Traverse each node in
queueCurrent
:- Add the node's value to the last list in
result
. - If the node has a left child, add it to
queueNext
. - If the node has a right child, add it to
queueNext
.
- Add the node's value to the last list in
- Clone
- After processing all levels, reverse the
result
list so that the bottom-most level appears first.
This implementation captures all levels in the tree and then reverses the list to ensure the traversal is from bottom to top. Utilize ArrayDeque
for efficient FIFO queue management and the dynamic resizing capability of ArrayList
to handle varying numbers of nodes at each tree level.
struct Element {
struct TreeNode* data;
struct Element* nextElement;
};
struct DataQueue {
struct Element *frontElement, *backElement;
};
struct Element* createNewElement(struct TreeNode* treeNode) {
struct Element* newElement = (struct Element*)malloc(sizeof(struct Element));
newElement->data = treeNode;
newElement->nextElement = NULL;
return newElement;
};
struct DataQueue* initializeQueue() {
struct DataQueue* newQueue = (struct DataQueue*)malloc(sizeof(struct DataQueue));
newQueue->frontElement = newQueue->backElement = NULL;
return newQueue;
};
void enqueue(struct DataQueue* queue, struct TreeNode* treeNode) {
struct Element* element = createNewElement(treeNode);
if (queue->backElement == NULL) {
queue->frontElement = queue->backElement = element;
return;
}
queue->backElement->nextElement = element;
queue->backElement = element;
}
void dequeue(struct DataQueue* queue) {
if (queue->frontElement == NULL) return;
struct Element* tempElement = queue->frontElement;
queue->frontElement = queue->frontElement->nextElement;
if (queue->frontElement == NULL) queue->backElement = NULL;
free(tempElement);
}
int** reversedLevelOrderTraversal(struct TreeNode* rootNode, int* returnSize, int** returnColumnSizes) {
int** levelsArray = malloc(sizeof(int*) * 10000);
*returnColumnSizes = malloc(sizeof(int) * 10000);
*returnSize = 0;
if (rootNode == NULL) return levelsArray;
struct DataQueue* rootQueue = initializeQueue();
enqueue(rootQueue, rootNode);
while (rootQueue->frontElement != NULL) {
struct DataQueue* tempQueue = initializeQueue();
levelsArray[*returnSize] = malloc(sizeof(int) * 2000);
(*returnColumnSizes)[*returnSize] = 0;
while (rootQueue->frontElement != NULL) {
struct TreeNode* currentNode = rootQueue->frontElement->data;
dequeue(rootQueue);
levelsArray[*returnSize][(*returnColumnSizes)[*returnSize]] = currentNode->val;
(*returnColumnSizes)[*returnSize]++;
if (currentNode->left) enqueue(tempQueue, currentNode->left);
if (currentNode->right) enqueue(tempQueue, currentNode->right);
}
*returnSize += 1;
rootQueue = tempQueue;
}
int start = 0, end = *returnSize - 1;
while (start < end) {
int tempCount = (*returnColumnSizes)[start];
int* tempLevel = levelsArray[start];
(*returnColumnSizes)[start] = (*returnColumnSizes)[end];
levelsArray[start] = levelsArray[end];
(*returnColumnSizes)[end] = tempCount;
levelsArray[end] = tempLevel;
start++;
end--;
}
return levelsArray;
}
In the provided solution for the problem of performing a reverse level order traversal on a binary tree, you implement several critical components in C:
Data Structures:
struct Element
: Represents an element in a queue, containing a pointer to aTreeNode
and a pointer to the next element.struct DataQueue
: Utilized to manage the queue operations with pointers to the front and back elements.
Queue Operations:
initializeQueue()
: Initializes an empty queue.enqueue()
: Adds a tree node to the end of the queue.dequeue()
: Removes a tree node from the front of the queue.createNewElement()
: Helper function to create a new queue element.
Traversal Logic:
reversedLevelOrderTraversal()
: Orchestrates the reverse level order traversal:- Initialize necessary structures and variables.
- Use a while loop to process each level of the tree.
- For each node at the current level, its children are added to a temporary queue.
- After processing all levels in normal order, the levels are reversed to achieve the desired reverse order.
The function handles dynamic memory allocation for the levels array and ensures proper memory management through the use of malloc
and free
. It also accommodates nodes at each level and appropriately adjusts the size of supporting arrays.
This approach ensures that you can perform the level order traversal and then simply reverse the results, thereby efficiently solving the problem using queue data structures standard in breadth-first traversal of trees.
var reverseLevelOrder = function (node) {
let result = [];
if (node == null) return result;
let queue = [node];
while (queue.length > 0) {
let levelNodes = [...queue];
queue = [];
result.unshift([]);
for (let item of levelNodes) {
result[0].push(item.val);
if (item.left != null) queue.push(item.left);
if (item.right != null) queue.push(item.right);
}
}
return result;
};
In this walkthrough, focus on implementing a function to perform a reverse level order traversal of a binary tree. This involves visiting all nodes of the tree in a bottom-up manner.
- Understand the main function
reverseLevelOrder
, which takes a parameternode
, referring to the root of the binary tree. - Declare an array
result
that will store the final reverse level order traversal output levels. - Start by checking if the input
node
isnull
. If it is, return an empty list immediately. - Utilize a
queue
to facilitate level order traversal by initiating it with the root node[node]
. - Use a while loop to process elements until the
queue
is empty, which implies all levels have been processed:- Copy
queue
tolevelNodes
to manage nodes at the current level. - Reset
queue
for the upcoming level. - Introduce a new sublist at the beginning of
result
withunshift
, allowing inverted stacking of node values. - Iterate over all nodes in
levelNodes
:- Append the current node's value to the first sublist in
result
. - Add the left child to the
queue
if it exists. - Add the right child to the
queue
if it exists.
- Append the current node's value to the first sublist in
- Copy
- End the while loop once all nodes are processed.
- Return the
result
which now contains all tree levels in reverse order.
Remember, this approach guarantees that each level of nodes is visited in a traditional level order but stored in reverse, achieving the desired bottom-up level order traversal.
class Solution:
def reverseLevelOrder(self, root: TreeNode) -> List[List[int]]:
results = []
queue = deque([root])
while root and queue:
current = queue
queue = deque()
results.append([])
for node in current:
results[-1].append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return results[::-1]
This Python code aims to solve the problem of performing a reverse level order traversal on a binary tree. The result should display the node values from the bottom to the top level, left to right within each level.
Here's a breakdown of the code process:
- Initialize an empty list
results
to hold the values of the tree nodes. - Use a
deque
(double-ended queue) to facilitate efficient popping from the front and appending to the back while traversing the binary tree. - Start with the root node in the queue.
- Use a while loop to continue processing as long as there are nodes in the queue.
- Inside the loop, utilize a for loop to iterate through nodes at the current level. Extract node values, and append them to the result list for that level.
- Manage node children by appending left and right children to the queue if available.
- After traversing all levels in normal order, reverse the
results
list to achieve the bottom-up level order traversal.
Ensure you have a TreeNode
class defined, which the function expects to receive as input. This function adjusts the tree node handling dynamically, storing results as lists of lists, with each sublist representing a level of the tree. The final returned list is reversed to match the bottom-up requirement.
No comments yet.