Given the root of a binary tree, return the zigzag level order traversal of its nodes' values. (i.e., from left to right, then right to left for the next level and alternate between).
Input : root = [1, 2, 3, null, 4, 8, 5]
Output : [ [1] , [3, 2], [4, 8, 5] ]
Explanation : So at root we move from left to right.
At next level we move in opposite direction i.e. from right to left.
At next level again reverse the traversal i.e. from left to right.
Input : root = [3, 9, 20, null, null, 15, 7]
Output : [ [3] , [20, 9], [15, 7] ]
Explanation : So at root we move from left to right.
At next level we move in opposite direction i.e. from right to left , from 20 to 9.
At next level again reverse the traversal i.e. from left to right, from 15 to 7.
Input : root = [5, 1, 2, 8, null, 4, 5, null, 6]
Zigzag traversal of a binary tree is an enhancement of the conventional level order traversal. While level order traversal explores nodes at each level from left to right, zigzag traversal adds an alternating pattern to the process. At odd levels, nodes are processed from left to right, but at even levels, the order is reversed, processing nodes from right to left. This alternation is controlled by a `leftToRight` flag, which determines the direction of node processing at each level. When `leftToRight` is true, nodes are inserted into the level vector from left to right, and when false, nodes are inserted from right to left.
leftToRight
flag to track the traversal direction. When leftToRight
is true, nodes are inserted into the level vector from left to right; when false, they are inserted from right to left.level
to store the nodes' values at the current level.level
vector (inserting from left to right if leftToRight
is true, or from right to left if false), and enqueue its child nodes (if they exist).level
vector to the ans
2D vector. Toggle the leftToRight
flag to reverse the traversal direction for the subsequent level.ans
2D vector, which contains the zigzag level-order traversal of the binary tree.#include <bits/stdc++.h>
using namespace std;
// Definition for a binary tree node.
struct TreeNode {
int data;
TreeNode *left;
TreeNode *right;
TreeNode(int val) : data(val), left(nullptr), right(nullptr) {}
};
class Solution {
public:
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
// Vector to store the result of zigzag traversal
vector<vector<int>> result;
// Check if the root is NULL, return an empty result
if (root == nullptr) {
return result;
}
// Queue to perform level order traversal
queue<TreeNode*> nodesQueue;
nodesQueue.push(root);
// Flag to determine the direction of traversal (left to right or right to left)
bool leftToRight = true;
// Continue traversal until the queue is empty
while (!nodesQueue.empty()) {
// Get the number of nodes at the current level
int size = nodesQueue.size();
// Vector to store the values of nodes at the current level
vector<int> row(size);
// Traverse nodes at the current level
for (int i = 0; i < size; i++) {
// Get the front node from the queue
TreeNode* node = nodesQueue.front();
nodesQueue.pop();
// Determine the index to insert the node's value based on the traversal direction
int index = leftToRight ? i : (size - 1 - i);
// Insert the node's value at the determined index
row[index] = node->data;
// Enqueue the left and right children if they exist
if (node->left) {
nodesQueue.push(node->left);
}
if (node->right) {
nodesQueue.push(node->right);
}
}
// Switch the traversal direction for the next level
leftToRight = !leftToRight;
// Add the current level's values to the result vector
result.push_back(row);
}
// Return the final result of zigzag level order traversal
return result;
}
};
// Helper function to print the result
void printResult(const vector<vector<int>>& result) {
for (const auto& row : result) {
for (int val : row) {
cout << val << " ";
}
cout << endl;
}
}
int main() {
// Creating a sample binary tree
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->left = new TreeNode(6);
root->right->right = new TreeNode(7);
Solution solution;
// Get the zigzag level order traversal
vector<vector<int>> result = solution.zigzagLevelOrder(root);
// Print the result
printResult(result);
return 0;
}
import java.util.*;
class TreeNode {
int data;
TreeNode left, right;
TreeNode(int val) { data = val; left = null; right = null; }
}
class Solution {
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
// List to store the result of zigzag traversal
List<List<Integer>> result = new ArrayList<>();
// Check if the root is NULL, return an empty result
if (root == null) {
return result;
}
// Queue to perform level order traversal
Queue<TreeNode> nodesQueue = new LinkedList<>();
nodesQueue.add(root);
// Flag to determine the direction of traversal (left to right or right to left)
boolean leftToRight = true;
// Continue traversal until the queue is empty
while (!nodesQueue.isEmpty()) {
// Get the number of nodes at the current level
int size = nodesQueue.size();
// List to store the values of nodes at the current level
List<Integer> row = new ArrayList<>(Collections.nCopies(size, 0));
// Traverse nodes at the current level
for (int i = 0; i < size; i++) {
// Get the front node from the queue
TreeNode node = nodesQueue.poll();
// Determine the index to insert the node's value based on the traversal direction
int index = leftToRight ? i : (size - 1 - i);
// Insert the node's value at the determined index
row.set(index, node.data);
// Enqueue the left and right children if they exist
if (node.left != null) {
nodesQueue.add(node.left);
}
if (node.right != null) {
nodesQueue.add(node.right);
}
}
// Switch the traversal direction for the next level
leftToRight = !leftToRight;
// Add the current level's values to the result list
result.add(row);
}
// Return the final result of zigzag level order traversal
return result;
}
}
// Helper function to print the result
class Main {
public static void printResult(List<List<Integer>> result) {
for (List<Integer> row : result) {
for (int val : row) {
System.out.print(val + " ");
}
System.out.println();
}
}
public static void main(String[] args) {
// Creating a sample binary tree
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.left = new TreeNode(6);
root.right.right = new TreeNode(7);
Solution solution = new Solution();
// Get the zigzag level order traversal
List<List<Integer>> result = solution.zigzagLevelOrder(root);
// Print the result
printResult(result);
}
}
from collections import deque
# Definition for a binary tree node.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
def zigzagLevelOrder(self, root):
# List to store the result of zigzag traversal
result = []
# Check if the root is NULL, return an empty result
if not root:
return result
# Queue to perform level order traversal
nodesQueue = deque([root])
# Flag to determine the direction of traversal (left to right or right to left)
leftToRight = True
# Continue traversal until the queue is empty
while nodesQueue:
# Get the number of nodes at the current level
size = len(nodesQueue)
# List to store the values of nodes at the current level
row = [0] * size
# Traverse nodes at the current level
for i in range(size):
# Get the front node from the queue
node = nodesQueue.popleft()
# Determine the index to insert the node's value based on the traversal direction
index = i if leftToRight else (size - 1 - i)
# Insert the node's value at the determined index
row[index] = node.val
# Enqueue the left and right children if they exist
if node.left:
nodesQueue.append(node.left)
if node.right:
nodesQueue.append(node.right)
# Switch the traversal direction for the next level
leftToRight = not leftToRight
# Add the current level's values to the result list
result.append(row)
# Return the final result of zigzag level order traversal
return result
# Helper function to print the result
def printResult(result):
for row in result:
print(" ".join(map(str, row)))
if __name__ == "__main__":
# Creating a sample binary tree
root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
root.left.left = TreeNode(4)
root.left.right = TreeNode(5)
root.right.left = TreeNode(6)
root.right.right = TreeNode(7)
solution = Solution()
# Get the zigzag level order traversal
result = solution.zigzagLevelOrder(root)
# Print the result
printResult(result)
/**
* Definition for a binary tree node.
* class TreeNode {
* constructor(val = 0, left = null, right = null){
* this.data = val;
* this.left = left;
* this.right = right;
* }
* }
**/
class Solution {
zigzagLevelOrder(root) {
// Array to store the result of zigzag traversal
let result = [];
// Check if the root is NULL, return an empty result
if (!root) {
return result;
}
// Queue to perform level order traversal
let nodesQueue = [];
nodesQueue.push(root);
// Flag to determine the direction of traversal (left to right or right to left)
let leftToRight = true;
// Continue traversal until the queue is empty
while (nodesQueue.length) {
// Get the number of nodes at the current level
let size = nodesQueue.length;
// Array to store the values of nodes at the current level
let row = new Array(size);
// Traverse nodes at the current level
for (let i = 0; i < size; i++) {
// Get the front node from the queue
let node = nodesQueue.shift();
// Determine the index to insert the node's value based on the traversal direction
let index = leftToRight ? i : (size - 1 - i);
// Insert the node's value at the determined index
row[index] = node.data;
// Enqueue the left and right children if they exist
if (node.left) {
nodesQueue.push(node.left);
}
if (node.right) {
nodesQueue.push(node.right);
}
}
// Switch the traversal direction for the next level
leftToRight = !leftToRight;
// Add the current level's values to the result array
result.push(row);
}
// Return the final result of zigzag level order traversal
return result;
}
}
// Helper function to print the result
function printResult(result) {
result.forEach(row => {
console.log(row.join(' '));
});
}
// Creating a sample binary tree
let 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.left = new TreeNode(6);
root.right.right = new TreeNode(7);
let solution = new Solution();
// Get the zigzag level order traversal
let result = solution.zigzagLevelOrder(root);
// Print the result
printResult(result);
Time Complexity: O(N) where N is the number of nodes in the binary tree. Each node of the binary tree is enqueued and dequeued exactly once, hence all nodes need to be processed and visited.
Space Complexity: O(N) where N is the number of nodes in the binary tree. In the worst case, the queue has to hold all the nodes of the last level of the binary tree, the last level could at most hold N/2 nodes hence the space complexity of the queue is proportional to O(N).
Q: Why is DFS not the preferred approach for this problem?
A: DFS explores depth-first, which does not naturally follow level-order traversal. While DFS can track depth and store nodes per level, we need extra logic to reverse odd levels, making it less intuitive than BFS.
Q: Can we just reverse every alternate level after traversal?
A: Yes, we can store all levels left to right, then reverse every alternate level before returning the result. However, this adds O(n) extra time complexity for reversing lists. A deque allows us to handle this efficiently during traversal.
Q: How would you modify the approach to return a spiral level-order traversal instead?
A: Spiral order traversal is similar but does not alternate direction at each level. Instead, nodes are processed in a strictly alternating spiral order (left to right → right to left → left to right).
Q: How would an iterative DFS implementation compare to BFS?
A: An iterative DFS would use a stack instead of a queue, keeping track of levels explicitly. However, maintaining zigzag order dynamically in DFS requires extra logic, making BFS more natural.