前端算法第一九一弹-二叉树中的伪回文路径

132 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第24天,点击查看活动详情

给你一棵二叉树,每个节点的值为 1 到 9 。我们称二叉树中的一条路径是 「伪回文 」的,当它满足:路径经过的所有节点值的排列中,存在一个回文序列。

请你返回从根到叶子节点的所有路径中 伪回文 路径的数目。

示例 1:

图片.png

输入: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:

图片.png

输入: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]

思路

总所周知 n & (n - 1) 可以用来消除最后一个1 举例: 以下都是二进制表示 假设 n = 100100 那么 n - 1 = 100011 因为100 - 1 = 011 那么 n & (n - 1) = 100000 所以这是去掉了最后的一个1

因为异或的性质是 位相同异或为0 位不同异或为1 例如 1 ^ 1 = 0 ; 1 ^ 0 =1 然后比如 5 二进制为 101 , 依据异或的性质 101 ^ 101 = 0 所以异或的性质就是两个相同的数 异或为0

然后回文串只会有两种情况 要么 1221 要么 121 所以异或后,要么是0 要么是个数为奇数的数字。 然后因为题目取值范围是1~9 所以可以用每一位代表一个数字。 比如5写成100000,这样哪怕是 121 这种情况 也只会剩下2 也就是100 这样我们就可以根据 n & (n - 1) 来消除1 所以判断是否为回文数字的条件就变成了

(n == 0 || (n & (n - 1)) == 0)

// 用来保存路径上元素的数量状态,记录奇数数目的元素个数
function Arrange(){
    this.map = new Map()
    this.odd_nums = 0
}
Arrange.prototype.push = function (x){
    if (!this.map.has(x)) this.map.set(x, 0)
    this.map.set(x, this.map.get(x)+1)

    if (this.map.get(x) % 2 === 0){
        this.odd_nums--
    }else{
        this.odd_nums++
    }

}
Arrange.prototype.pop = function(x){
    this.map.set(x, this.map.get(x)-1)
    
    if (this.map.get(x) % 2 === 0){
        this.odd_nums--
    }else{
        this.odd_nums++
    }

}
var pseudoPalindromicPaths  = function(root) {
    if (!root) return 0
    let arrange = new Arrange()
    let res = 0
    function dfs(root){
        
        arrange.push(root.val)
        if (!root.left && !root.right){
            if (arrange.odd_nums < 2) res++
        }

        if (root.left) dfs(root.left)
        if (root.right) dfs(root.right)
        arrange.pop(root.val)
    }
    dfs(root)
    return res

};