1. 问题描述:
给你一棵二叉树,每个节点的值为 1 到 9 。我们称二叉树中的一条路径是 「伪回文」的,当它满足:路径经过的所有节点值的排列中,存在一个回文序列。
请你返回从根到叶子节点的所有路径中 伪回文 路径的数目。
示例 1:
输入:root = [2,3,1,3,1,null,1]
输出:2
解释:上图为给定的二叉树。总共有 3 条从根到叶子的路径:红色路径 [2,3,3] ,绿色路径 [2,1,1] 和路径 [2,3,1] 。在这些路径中,只有红色和绿色的路径是伪回文路径,因为红色路径 [2,3,3] 存在回文排列 [3,2,3] ,绿色路径 [2,1,1] 存在回文排列 [1,2,1] 。
示例 2:
输入:root = [2,1,1,1,3,null,null,null,null,null,1]
输出:1
解释:上图为给定二叉树。总共有 3 条从根到叶子的路径:绿色路径 [2,1,1] ,路径 [2,1,3,1] 和路径 [2,1] 。这些路径中只有绿色路径是伪回文路径,因为 [2,1,1] 存在回文排列 [1,2,1] 。
示例 3:
输入:root = [9]
输出:1
提示:
给定二叉树的节点数目在 1 到 10^5 之间。
节点值在 1 到 9 之间
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/pseudo-palindromic-paths-in-a-binary-tree
2. 思路分析:
① 题目不难理解,首先我们是需要找到从根节点到叶子节点之间的路径,毫无疑问可以使用递归来找到这些路径,其实这道题目的难点在于如何如何判断是否是伪回文,我们之前经常判断的字符串或者数字是否是回文串,其实这里的伪回文也很好判断,我们找到从根节点到叶子节点的路径之后假如这条路径上的数字经过重新排列之后是对称的那么就是伪回文,所以从这里可以看出一个规律是回文是对称的,所以我们只需要判断出数字中有多少个数字出现的次数是奇数的就可以判断是否可以构成回文,这里又可以想到map中一个比较强大的功能那就是计数,通过map来统计相同的数字出现的次数
② 我们可以声明一个全局的map,在递归之前我们需要对当前根节点的值出现的次数加1,然后往下递归,当到达了叶子节点的时候那么循环判断map中存储的数字出现的次数,假如是回文串那么对应数字出现的次数只有一个奇数次或者是没有奇数次,这样就就相当于可以判断出这些数字经过重新组合之后是否可以构成回文串了,其实这也是利用了回文的一个特点:相互对称,还需要注意的是我们在递归之后需要进行回溯,将之前加入的节点值对应的次数减1
3. 代码如下:
class Solution {
int res;
Map<Integer, Integer> map = new HashMap<>();
public int pseudoPalindromicPaths (TreeNode root) {
dfs(root);
return res;
}
private void dfs(TreeNode root) {
if (root == null) return;
/*叶子节点: 检查一下*/
if (root.left == null && root.right == null){
/*需要加入最后的叶子节点*/
map.put(root.val, map.getOrDefault(root.val, 0) + 1);
/*检查是否是伪回文: 遍历map中检查对应数字是奇数个还是偶数个*/
int odds = 0, flag = 1;
for (Map.Entry<Integer, Integer> entry : map.entrySet()){
if (entry.getValue() % 2 != 0) ++odds;
if (odds > 1){
flag = 0;
break;
}
}
/*回溯*/
map.put(root.val, map.getOrDefault(root.val, 0) - 1);
if (flag == 1) ++res;
return;
}
/*加入的是当前的根节点*/
map.put(root.val, map.getOrDefault(root.val, 0) + 1);
dfs(root.left);
dfs(root.right);
/*回溯*/
map.put(root.val, map.getOrDefault(root.val, 0) - 1);
}
}