Pseudo-Palindromic Paths in a Binary Tree
MedPrompt
Given a binary tree where node values are digits from 1 to 9. A path in the binary tree is said to be pseudo-palindromic if at least one permutation of the node values in the path is a palindrome.
Return the number of pseudo-palindromic paths going from the root node to leaf nodes.
Example 1:

Input: root = [2,3,1,3,1,null,1]
Output: 2
Explanation: The figure above represents the given binary tree. There are three paths going from the root node to leaf nodes: the red path [2,3,3], the green path [2,1,1], and the path [2,3,1]. Among these paths only red path and green path are pseudo-palindromic paths since the red path [2,3,3] can be rearranged in [3,2,3] (palindrome) and the green path [2,1,1] can be rearranged in [1,2,1] (palindrome).Example 2:

Input: root = [2,1,1,1,3,null,null,null,null,null,1]
Output: 1
Explanation: The figure above represents the given binary tree. There are three paths going from the root node to leaf nodes: the green path [2,1,1], the path [2,1,3,1], and the path [2,1]. Among these paths only the green path is pseudo-palindromic since [2,1,1] can be rearranged in [1,2,1] (palindrome).Example 3:
Input: root = [9]
Output: 1
Constraints:
- The number of nodes in the tree is in the range
[1, 105]. 1 <= Node.val <= 9
Approaches
2 approaches with complexity analysis and trade-offs.
This approach uses a standard Depth-First Search (DFS) to traverse the tree from the root to each leaf. During the traversal, it maintains a frequency count of the digits encountered along the current path. When a leaf node is reached, it checks if the path is pseudo-palindromic by analyzing these counts.
Algorithm
- Initialize a global or member variable
countto 0. - Create a frequency array
countsof size 10, initialized to all zeros, to store the frequency of digits 1 through 9. - Define a recursive DFS function, let's call it
dfs(node, counts). - In the
dfsfunction:- If the current
nodeis null, return immediately. - Increment the frequency of the current node's value:
counts[node.val]++. - Check if the current node is a leaf node (i.e.,
node.left == null && node.right == null).- If it is a leaf, check if the current path is pseudo-palindromic. This is done by a helper function that iterates through the
countsarray and counts how many digits have an odd frequency. If the number of odd-frequency digits is 0 or 1, increment the globalcount.
- If it is a leaf, check if the current path is pseudo-palindromic. This is done by a helper function that iterates through the
- Recursively call the function for the left and right children:
dfs(node.left, counts)anddfs(node.right, counts). - Backtrack: After the recursive calls for the children return, decrement the frequency of the current node's value:
counts[node.val]--. This step is crucial to correctly reflect the path state as the traversal unwinds.
- If the current
- Start the traversal by calling
dfs(root, counts)from the main function. - Return the final
count.
Walkthrough
A path's node values can form a palindrome if at most one digit appears an odd number of times. We can implement a recursive DFS function, say dfs(node, counts), that explores the tree. The counts parameter is an array that stores the frequency of each digit (1-9) from the root to the current node.
The main function initializes a counter for pseudo-palindromic paths to zero and an empty frequency array, then calls dfs(root, counts). The key to this approach is backtracking. After visiting a node and its descendants, we must undo the change made to the frequency count for that node. This ensures that when we explore a sibling branch, the counts accurately represent the path to that sibling's parent, not the path through the previously explored cousin nodes.
/** * 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 count = 0; public int pseudoPalindromicPaths (TreeNode root) { int[] pathCounts = new int[10]; dfs(root, pathCounts); return count; } private void dfs(TreeNode node, int[] pathCounts) { if (node == null) { return; } // Add current node to the path pathCounts[node.val]++; // If it's a leaf node, check for pseudo-palindrome if (node.left == null && node.right == null) { if (isPseudoPalindrome(pathCounts)) { count++; } } else { // Continue traversal dfs(node.left, pathCounts); dfs(node.right, pathCounts); } // Backtrack: remove current node from the path pathCounts[node.val]--; } private boolean isPseudoPalindrome(int[] counts) { int oddCount = 0; for (int i = 1; i <= 9; i++) { if (counts[i] % 2 != 0) { oddCount++; } } return oddCount <= 1; }}Complexity
Time
O(N), where N is the number of nodes in the tree. We visit each node exactly once. At each leaf node, we perform a check that takes constant time (iterating 9 times), so the overall complexity is proportional to the number of nodes.
Space
O(H), where H is the height of the tree. The space is dominated by the recursion stack depth. In the worst case of a skewed tree, H can be equal to N (the number of nodes), leading to O(N) space. The frequency array uses constant O(1) space.
Trade-offs
Pros
Conceptually straightforward and easy to understand.
Directly models the problem by counting frequencies, making the logic clear.
Cons
Slightly less performant than the bitmasking approach due to the overhead of iterating through the frequency array at each leaf.
Requires careful implementation of backtracking to avoid incorrect counts and to manage memory efficiently.
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 int pseudoPalindromicPaths ( TreeNode root ) { return dfs ( root , 0 ); } private int dfs ( TreeNode root , int mask ) { if ( root == null ) { return 0 ; } mask ^= 1 << root . val ; if ( root . left == null && root . right == null ) { return ( mask & ( mask - 1 )) == 0 ? 1 : 0 ; } return dfs ( root . left , mask ) + dfs ( root . right , mask ); } }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.