0% completed
Problem Statement
Given a binary tree where each node has a value between 1
and 9
, return the number of "pseudo-palindromic"
paths from the root node to any leaf node.
A path is called "pseudo-palindromic"
if the values along the path can be rearranged to form a palindrome.
Examples
Example 1
- Input:
5 / \ 4 1 / \ \ 4 1 1
- Expected Output: 2
- Justification: The paths are:
- 5 → 4 → 4 (pseudo-palindromic: "5, 4, 4" can be rearranged to "4, 5, 4")
- 5 → 1 → 1 (pseudo-palindromic: "5, 1, 1" can be rearranged to "1, 5, 1")
Example 2
- Input:
2 / \ 3 1 / / \ 3 1 1
- Expected Output: 3
- Justification: All 3 paths are pseudo-palindromic paths.
Example 3
- Input:
9 / \ 5 5 / / \ 5 1 7
- Expected Output: 1
- Justification: The only path 9 → 5 → 5 is a psuedo-palindromic path.
Constraints:
- The number of nodes in the tree is in the range [1, 10<sup>5</sup>].
- 1 <= Node.val <= 9
Solution
To solve this problem, we will traverse the binary tree using Depth-First Search (DFS). During the traversal, we will keep track of the count of each digit in the current path using an array. For each leaf node, we will check if the path from the root to this node is pseudo-palindromic by verifying if at most one digit has an odd count. This check is based on the property of palindromes, where at most one character can have an odd frequency.
Our approach will be effective because it leverages the tree's structure and efficiently checks for pseudo-palindromic paths using counting and simple arithmetic operations.
Step-by-step Algorithm
-
Initialize a Function:
- Define a function
pseudoPalindromicPaths
which takes the root of the binary tree as input.
- Define a function
-
Depth-First Search (DFS) Helper Function:
- Inside
pseudoPalindromicPaths
, define a helper functiondfs
which will perform the depth-first search. This function takes a node and a path (represented as an integer) as input.
- Inside
-
Base Case for DFS:
- In the
dfs
function, check if the node isnull
. If it is, return0
.
- In the
-
Update Path:
- Toggle the bit corresponding to the current node's value in the path using the XOR operation (
path ^= 1 << node.val
).
- Toggle the bit corresponding to the current node's value in the path using the XOR operation (
-
Check if Leaf Node:
- Check if the current node is a leaf node (i.e., it has no left or right child). If it is a leaf, check if at most one bit is set in the path (which means the path can form a palindrome). This can be checked using
(path & (path - 1)) == 0
. If the condition is true, return1
, otherwise return0
.
- Check if the current node is a leaf node (i.e., it has no left or right child). If it is a leaf, check if at most one bit is set in the path (which means the path can form a palindrome). This can be checked using
-
Recursive DFS Calls:
- If the current node is not a leaf, recursively call
dfs
for the left and right children of the node, passing the updated path as the argument.
- If the current node is not a leaf, recursively call
-
Combine Results:
- Sum the results of the left and right recursive calls and return the total count.
-
Return Final Result:
- In the
pseudoPalindromicPaths
function, call thedfs
function with the root node and an initial path of0
. Return the result.
- In the
Algorithm Walkthrough
Let's walk through the algorithm step-by-step using the provided binary tree:
5
/ \
4 1
/ \ \
4 1 1
-
Call pseudoPalindromicPaths with root:
pseudoPalindromicPaths(root)
is called with the root node (value 5).
-
Initialize DFS with root node and path = 0:
dfs(root, 0)
is called with root node (value 5) and path = 0.
-
DFS at node 5:
- Update path:
path ^= 1 << 5
→ path = 00000000 ^ 00010000 = 00010000. - Node 5 is not a leaf. Proceed with recursive calls.
- Update path:
-
DFS at node 4 (left child of 5):
- Update path:
path ^= 1 << 4
→ path = 00010000 ^ 00001000 = 00011000. - Node 4 is not a leaf. Proceed with recursive calls.
- Update path:
-
DFS at node 4 (left child of 4):
- Update path:
path ^= 1 << 4
→ path = 00011000 ^ 00001000 = 00010000. - Node 4 is a leaf. Check if path can form a palindrome:
(00010000 & (00010000- 1)) == 0
→ true. - Return 1.
- Update path:
-
DFS at node 1 (right child of 4):
- Update path:
path ^= 1 << 1
→ path = 00011000 ^ 00000010 = 00011010. - Node 1 is a leaf. Check if path can form a palindrome:
(00011010 & (00011010 - 1)) == 0
→ false. - Return 0.
- Update path:
-
Combine results at node 4:
- Results from left and right children: 1 + 0 = 1.
- Return 1.
-
DFS at node 1 (right child of 5):
- Update path:
path ^= 1 << 1
→ path = 00010000 ^ 00000010 = 00010010. - Node 1 is not a leaf. Proceed with recursive calls.
- Update path:
-
DFS at node 1 (right child of 1):
- Update path:
path ^= 1 << 1
→ path = 00010010 ^ 00000010 = 00010000. - Node 1 is a leaf. Check if path can form a palindrome:
(32 & (32 - 1)) == 0
→ true. - Return 1.
- Update path:
-
Combine results at node 1 (right child of 5):
- Results from left and right children: 0 + 1 = 1.
- Return 1.
-
Combine results at root node 5:
- Results from left and right children: 1 + 1 = 2.
- Return 2.
Code
Complexity Analysis
Time Complexity
- The algorithm visits each node exactly once, performing constant-time operations for each node (bit manipulation and checking if it's a leaf). Thus, the time complexity is O(N), where N is the number of nodes in the binary tree.
Space Complexity
- The space complexity is determined by the depth of the recursion stack, which is proportional to the height of the tree (H). In the worst case, this could be O(N) for a skewed tree. However, for a balanced tree, it is O(log N).
.....
.....
.....
Table of Contents
Contents are not accessible
Contents are not accessible
Contents are not accessible
Contents are not accessible
Contents are not accessible