Longest ZigZag Path in a Binary Tree
MEDIUMDescription
You are given the root of a binary tree.
A ZigZag path for a binary tree is defined as follow:
- Choose any node in the binary tree and a direction (right or left).
- If the current direction is right, move to the right child of the current node; otherwise, move to the left child.
- Change the direction from right to left or from left to right.
- Repeat the second and third steps until you can't move in the tree.
Zigzag length is defined as the number of nodes visited - 1. (A single node has a length of 0).
Return the longest ZigZag path contained in that tree.
Example 1:
Input: root = [1,null,1,1,1,null,null,1,1,null,1,null,null,null,1] Output: 3 Explanation: Longest ZigZag path in blue nodes (right -> left -> right).
Example 2:
Input: root = [1,1,1,null,1,null,null,1,1,null,1] Output: 4 Explanation: Longest ZigZag path in blue nodes (left -> right -> left -> right).
Example 3:
Input: root = [1] Output: 0
Constraints:
- The number of nodes in the tree is in the range
[1, 5 * 104]. 1 <= Node.val <= 100
Approaches
Checkout 2 different approaches to solve Longest ZigZag Path in a Binary Tree. Click on different approaches to view the approach and algorithm in detail.
Optimal Single-Pass DFS
A more efficient approach is to use a single Depth First Search (DFS) pass. By employing a post-order traversal, we can compute the necessary information for a node based on the results from its children. For each node, we calculate the length of the longest ZigZag path starting at that node and going left, and the length of the path starting at that node and going right. This information is then 'bubbled up' to the parent node, which uses it to compute the lengths of its own starting paths. A global variable is used to keep track of the maximum length found at any point in the traversal.
Algorithm
- Use a single Depth First Search (DFS) traversal, specifically a post-order traversal.
- Define a recursive helper function,
dfs(node), that returns information about paths starting atnode. - The
dfs(node)function will return an array of two integers:[leftPath, rightPath].leftPath: The length of the longest ZigZag path that starts atnodeand first goes to the left.rightPath: The length of the longest ZigZag path that starts atnodeand first goes to the right.
- The base case for the recursion is when
nodeisnull. In this case, return[-1, -1]to indicate that no path exists, which simplifies the calculation for the parent. - For a non-null
node, recursively calldfson its children:leftResult = dfs(node.left)andrightResult = dfs(node.right). - To calculate
leftPathfor the currentnode: a path going left fromnodemust then continue fromnode.leftby going right. So,leftPath = 1 + leftResult[1]. - Similarly,
rightPath = 1 + rightResult[0]. - Maintain a global
maxLengthvariable. After computingleftPathandrightPathfor the currentnode, updatemaxLength = max(maxLength, leftPath, rightPath). - The
dfsfunction returns the[leftPath, rightPath]array for its parent to use.
This optimal solution avoids re-computation by solving the problem in a single pass using a post-order DFS traversal. The core idea is to use the return value of the recursive calls to pass information up the tree.
Our recursive function, dfs(node), will return an array of two integers for each node. The first element will be the length of the longest ZigZag path starting at node with a left move, and the second will be the length of the path starting with a right move.
When dfs(node) is called:
- It first calls itself on its left and right children.
- It receives the results from its children. For example,
leftResultfromdfs(node.left)contains the lengths of paths starting atnode.left. - To find the length of a ZigZag path starting at
nodeand going left, we take one step tonode.left(length 1) and then continue the ZigZag. The next move must be to the right. The length of the longest ZigZag path starting fromnode.leftand going right is given byleftResult[1]. So, the total length is1 + leftResult[1]. - Similarly, the length of a path starting at
nodeand going right is1 + rightResult[0]. - We update a global
maxLengthwith the maximum of these two calculated lengths. This ensures we track the longest path found anywhere in the tree. - Finally, the function returns the newly computed lengths for
nodeto its parent.
/**
* Definition for a binary tree node.
* public 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;
* }
* }
*/
class Solution {
int maxLength = 0;
public int longestZigZag(TreeNode root) {
dfs(root);
return maxLength;
}
/**
* Performs a post-order traversal to calculate ZigZag path lengths.
* @return an array of two elements:
* result[0] = longest ZigZag path starting from 'node' and going LEFT.
* result[1] = longest ZigZag path starting from 'node' and going RIGHT.
*/
private int[] dfs(TreeNode node) {
if (node == null) {
// Base case: no path exists from a null node.
// -1 helps in calculation: 1 + (-1) = 0 for a path of a single node.
return new int[]{-1, -1};
}
// Recursively get results from children
int[] leftResult = dfs(node.left);
int[] rightResult = dfs(node.right);
// Calculate path starting at current node and going left.
// This path continues from the left child by going right.
int pathStartingLeft = 1 + leftResult[1];
// Calculate path starting at current node and going right.
// This path continues from the right child by going left.
int pathStartingRight = 1 + rightResult[0];
// Update the global maximum length found so far.
maxLength = Math.max(maxLength, Math.max(pathStartingLeft, pathStartingRight));
// Return the lengths of paths starting at the current node for the parent.
return new int[]{pathStartingLeft, pathStartingRight};
}
}
Complexity Analysis
Pros and Cons
- Optimal time complexity of O(N) as it visits each node only once.
- Efficient use of space, proportional to the height of the tree.
- The recursive logic, especially the meaning of the returned array, can be slightly less intuitive to grasp initially compared to the brute-force approach.
Code Solutions
Checking out 3 solutions in different languages for Longest ZigZag Path in a Binary Tree. Click on different languages to view the code.
/** * Definition for a binary tree node. * public 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; * } * } */ class Solution { private int ans ; public int longestZigZag ( TreeNode root ) { dfs ( root , 0 , 0 ); return ans ; } private void dfs ( TreeNode root , int l , int r ) { if ( root == null ) { return ; } ans = Math . max ( ans , Math . max ( l , r )); dfs ( root . left , r + 1 , 0 ); dfs ( root . right , 0 , l + 1 ); } }Video Solution
Watch the video walkthrough for Longest ZigZag Path in a Binary Tree
Similar Questions
5 related questions you might find useful
Algorithms:
Patterns:
Data Structures:
Companies:
Subscribe to Scale Engineer newsletter
Learn about System Design, Software Engineering, and interview experiences every week.
No spam, unsubscribe at any time.