Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from left to right, then right to left for the next level and alternate between).
Example:
Input: root = [3, 9, 20, null, null, 15, 7]
3
/ \
9 20
/ \
15 7
Output:
[
[3],
[20,9],
[15,7]
]
The core challenge of this problem is to traverse the binary tree in a zigzag manner. This means that for each level of the tree, the traversal direction alternates between left-to-right and right-to-left. This type of traversal is significant in scenarios where hierarchical data needs to be processed in a non-linear order.
To solve this problem, we can use a breadth-first search (BFS) approach with a queue to traverse the tree level by level. We will also use a flag to keep track of the current direction of traversal (left-to-right or right-to-left). For each level, we will collect the nodes' values and reverse the order if the current direction is right-to-left.
A naive solution would involve traversing the tree level by level and then reversing the order of nodes for every alternate level. However, this approach is not optimal as reversing the list at each level adds unnecessary complexity.
An optimized solution involves using a deque (double-ended queue) to efficiently add nodes from both ends based on the current traversal direction. This avoids the need to reverse the list at each level.
#include <iostream>
#include <vector>
#include <deque>
#include <queue>
using namespace std;
// Definition for a binary tree node.
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
vector<vector<int>> result;
if (!root) return result;
queue<TreeNode*> nodeQueue;
nodeQueue.push(root);
bool leftToRight = true;
while (!nodeQueue.empty()) {
int levelSize = nodeQueue.size();
deque<int> levelNodes;
for (int i = 0; i < levelSize; ++i) {
TreeNode* currentNode = nodeQueue.front();
nodeQueue.pop();
if (leftToRight) {
levelNodes.push_back(currentNode->val);
} else {
levelNodes.push_front(currentNode->val);
}
if (currentNode->left) nodeQueue.push(currentNode->left);
if (currentNode->right) nodeQueue.push(currentNode->right);
}
result.push_back(vector<int>(levelNodes.begin(), levelNodes.end()));
leftToRight = !leftToRight;
}
return result;
}
// Helper function to create a new tree node
TreeNode* newNode(int data) {
TreeNode* node = new TreeNode(data);
node->left = node->right = NULL;
return node;
}
// Main function to test the zigzag traversal
int main() {
TreeNode* root = newNode(3);
root->left = newNode(9);
root->right = newNode(20);
root->right->left = newNode(15);
root->right->right = newNode(7);
vector<vector<int>> result = zigzagLevelOrder(root);
for (const auto& level : result) {
for (int val : level) {
cout << val << " ";
}
cout << endl;
}
return 0;
}
The time complexity of this solution is O(n), where n is the number of nodes in the binary tree. This is because each node is processed exactly once. The space complexity is also O(n) due to the storage required for the result and the queue used for BFS.
Some potential edge cases include:
To test the solution comprehensively, consider the following test cases:
When approaching such problems, consider the following tips:
In this blog post, we discussed the zigzag level order traversal of a binary tree. We explored the problem definition, approach, algorithm, and provided a detailed C++ implementation. We also analyzed the complexity and discussed edge cases and testing strategies. Understanding and solving such problems is crucial for improving problem-solving skills and preparing for technical interviews.
For further reading and practice, consider the following resources: