Forgetting null/base-case handling
Wrong move: Recursive traversal assumes children always exist.
Usually fails on: Leaf nodes throw errors or create wrong depth/path values.
Fix: Handle null/base cases before recursive transitions.
Move from brute-force thinking to an efficient approach using bit manipulation strategy.
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:
[1, 105].1 <= Node.val <= 9Problem summary: 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.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Bit Manipulation · Tree
[2,3,1,3,1,null,1]
[2,1,1,1,3,null,null,null,null,null,1]
[9]
Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #1457: Pseudo-Palindromic Paths in a Binary Tree
/**
* 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);
}
}
// Accepted solution for LeetCode #1457: Pseudo-Palindromic Paths in a Binary Tree
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func pseudoPalindromicPaths(root *TreeNode) int {
var dfs func(*TreeNode, int) int
dfs = func(root *TreeNode, mask int) int {
if root == nil {
return 0
}
mask ^= 1 << root.Val
if root.Left == nil && root.Right == nil {
if mask&(mask-1) == 0 {
return 1
}
return 0
}
return dfs(root.Left, mask) + dfs(root.Right, mask)
}
return dfs(root, 0)
}
# Accepted solution for LeetCode #1457: Pseudo-Palindromic Paths in a Binary Tree
# 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 pseudoPalindromicPaths(self, root: Optional[TreeNode]) -> int:
def dfs(root: Optional[TreeNode], mask: int):
if root is None:
return 0
mask ^= 1 << root.val
if root.left is None and root.right is None:
return int((mask & (mask - 1)) == 0)
return dfs(root.left, mask) + dfs(root.right, mask)
return dfs(root, 0)
// Accepted solution for LeetCode #1457: Pseudo-Palindromic Paths in a Binary Tree
// Definition for a binary tree node.
// #[derive(Debug, PartialEq, Eq)]
// pub struct TreeNode {
// pub val: i32,
// pub left: Option<Rc<RefCell<TreeNode>>>,
// pub right: Option<Rc<RefCell<TreeNode>>>,
// }
//
// impl TreeNode {
// #[inline]
// pub fn new(val: i32) -> Self {
// TreeNode {
// val,
// left: None,
// right: None
// }
// }
// }
use std::cell::RefCell;
use std::rc::Rc;
impl Solution {
pub fn pseudo_palindromic_paths(root: Option<Rc<RefCell<TreeNode>>>) -> i32 {
fn dfs(root: Option<Rc<RefCell<TreeNode>>>, mask: i32) -> i32 {
if let Some(node) = root {
let mut mask = mask;
let val = node.borrow().val;
mask ^= 1 << val;
if node.borrow().left.is_none() && node.borrow().right.is_none() {
return if (mask & (mask - 1)) == 0 { 1 } else { 0 };
}
return (dfs(node.borrow().left.clone(), mask)
+ dfs(node.borrow().right.clone(), mask));
}
0
}
dfs(root, 0)
}
}
// Accepted solution for LeetCode #1457: Pseudo-Palindromic Paths in a Binary Tree
/**
* Definition for a binary tree node.
* class TreeNode {
* val: number
* left: TreeNode | null
* right: TreeNode | null
* constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
* }
*/
function pseudoPalindromicPaths(root: TreeNode | null): number {
const dfs = (root: TreeNode | null, mask: number): number => {
if (!root) {
return 0;
}
mask ^= 1 << root.val;
if (!root.left && !root.right) {
return (mask & (mask - 1)) === 0 ? 1 : 0;
}
return dfs(root.left, mask) + dfs(root.right, mask);
};
return dfs(root, 0);
}
Use this to step through a reusable interview workflow for this problem.
Sort the array in O(n log n), then scan for the missing or unique element by comparing adjacent pairs. Sorting requires O(n) auxiliary space (or O(1) with in-place sort but O(n log n) time remains). The sort step dominates.
Bitwise operations (AND, OR, XOR, shifts) are O(1) per operation on fixed-width integers. A single pass through the input with bit operations gives O(n) time. The key insight: XOR of a number with itself is 0, which eliminates duplicates without extra space.
Review these before coding to avoid predictable interview regressions.
Wrong move: Recursive traversal assumes children always exist.
Usually fails on: Leaf nodes throw errors or create wrong depth/path values.
Fix: Handle null/base cases before recursive transitions.