Even Odd Tree
MedPrompt
A binary tree is named Even-Odd if it meets the following conditions:
- The root of the binary tree is at level index
0, its children are at level index1, their children are at level index2, etc. - For every even-indexed level, all nodes at the level have odd integer values in strictly increasing order (from left to right).
- For every odd-indexed level, all nodes at the level have even integer values in strictly decreasing order (from left to right).
Given the root of a binary tree, return true if the binary tree is Even-Odd, otherwise return false.
Example 1:
Input: root = [1,10,4,3,null,7,9,12,8,6,null,null,2]
Output: true
Explanation: The node values on each level are:
Level 0: [1]
Level 1: [10,4]
Level 2: [3,7,9]
Level 3: [12,8,6,2]
Since levels 0 and 2 are all odd and increasing and levels 1 and 3 are all even and decreasing, the tree is Even-Odd.Example 2:
Input: root = [5,4,2,3,3,7]
Output: false
Explanation: The node values on each level are:
Level 0: [5]
Level 1: [4,2]
Level 2: [3,3,7]
Node values in level 2 must be in strictly increasing order, so the tree is not Even-Odd.Example 3:
Input: root = [5,9,1,3,5,7]
Output: false
Explanation: Node values in the level 1 should be even integers.
Constraints:
- The number of nodes in the tree is in the range
[1, 105]. 1 <= Node.val <= 106
Approaches
2 approaches with complexity analysis and trade-offs.
This approach uses a recursive Depth-First Search (DFS) to traverse the tree. To enforce the ordering constraints (strictly increasing/decreasing) at each level, we need to keep track of the last value encountered at every level. A list can be used for this purpose, where the index corresponds to the tree level. A pre-order traversal ensures that nodes at a given level are processed from left to right.
Algorithm
- Use a recursive helper function
dfs(node, level). - Maintain a list,
lastValues, wherelastValues.get(level)stores the value of the previously visited node at thatlevel. - The traversal must be pre-order (
root,left,right) to ensure nodes at the same level are visited from left to right. - Base Case: If
nodeisnull, returntrue. - Parity Check:
- If
levelis even,node.valmust be odd. If not, returnfalse. - If
levelis odd,node.valmust be even. If not, returnfalse.
- If
- Order Check:
- If it's the first node at this
level(i.e.,level >= lastValues.size()), add its value tolastValues. - Otherwise, get
prevVal = lastValues.get(level). - For an even
level, check ifnode.val > prevVal. If not, returnfalse. - For an odd
level, check ifnode.val < prevVal. If not, returnfalse. - If the check passes, update
lastValues.set(level, node.val).
- If it's the first node at this
- Recursive Step: Return
trueonly if the recursive calls for both left and right children,dfs(node.left, level + 1)anddfs(node.right, level + 1), returntrue.
Walkthrough
We perform a pre-order traversal (root, left, right) of the tree. This ensures that for any given level, we visit the nodes from left to right.
A helper function, say dfs(node, level), is used. It takes the current node and its level as arguments.
We maintain a list, lastValues, accessible by the recursive calls, where lastValues.get(level) stores the value of the previously visited node at that level.
import java.util.ArrayList;import java.util.List; /** * 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 { // List to store the last seen value at each level private List<Integer> lastValues = new ArrayList<>(); public boolean isEvenOddTree(TreeNode root) { return dfs(root, 0); } private boolean dfs(TreeNode node, int level) { if (node == null) { return true; } // Condition 1: Parity check based on level // If level is even, value must be odd. If level is odd, value must be even. // This is equivalent to checking if level and value have different parity. if (level % 2 == node.val % 2) { return false; } // Condition 2: Order check // If this is the first node we've seen at this level if (level >= lastValues.size()) { lastValues.add(node.val); } else { int prevVal = lastValues.get(level); // Even level: must be strictly increasing if (level % 2 == 0) { if (node.val <= prevVal) { return false; } } // Odd level: must be strictly decreasing else { if (node.val >= prevVal) { return false; } } // Update the last value for the current level lastValues.set(level, node.val); } // Recurse for children return dfs(node.left, level + 1) && dfs(node.right, level + 1); }}Complexity
Time
O(N), where N is the number of nodes in the tree. Each node is visited exactly once.
Space
O(H), where H is the height of the tree. This space is used by the recursion stack and the `lastValues` list. In the worst case of a skewed tree, H can be equal to N (the number of nodes), leading to O(N) space complexity.
Trade-offs
Pros
Conceptually straightforward implementation of tree traversal.
Cons
Can cause a
StackOverflowErrorfor very deep trees due to the depth of recursion.The space complexity depends on the tree's height, which can be O(N) for skewed trees, making it less memory-efficient in such cases compared to BFS.
Solutions
Solution
/** * 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 { public boolean isEvenOddTree ( TreeNode root ) { Queue < TreeNode > que = new LinkedList < > (); que . add ( root ); que . add ( null ); int res = 1 ; int c = 0 ; int prev = 0 ; while (! que . isEmpty ()) { if ( res % 2 == 0 ) prev = Integer . MAX_VALUE ; else prev = Integer . MIN_VALUE ; while ( que . peek () != null ) { if ( que . peek (). val % 2 != res % 2 ) { return false ; } if ( res % 2 == 0 && prev <= que . peek (). val ) { return false ; } if ( res % 2 != 0 && prev >= que . peek (). val ) return false ; if ( que . peek (). left != null ) que . add ( que . peek (). left ); if ( que . peek (). right != null ) que . add ( que . peek (). right ); prev = que . poll (). val ; } que . poll (); if ( que . isEmpty ()) { break ; } res ++; que . add ( null ); } return true ; } }Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.