树中可以形成回文的路径数

发布时间 2023-07-25 03:55:36作者: 失控D大白兔

找出满足 u < v ,且从 u 到 v 的路径上分配的字符可以重新排列形成回文的所有节点对 (u, v) ,并返回节点对的数目。
如果一个字符串正着读和反着读都相同,那么这个字符串就是一个回文

1. 二进制状态压缩 + 深度优先搜索 + 哈希

class Solution {
public:
    long long countPalindromePaths(vector<int>& parent, string s) {
        //重新排列形成回文串,表示奇数次的字符最多存在一个
        //首先根据静态索引构建树,这里直接建图
        int n = parent.size();
        vector<vector<int>> graph(n);
        for(int i=1;i<n;i++)
            graph[parent[i]].push_back(i);//只存储每个顶点的后继
        long long res = 0;
        unordered_map<int,int> m;//记录根节点到子节点路径状态个数
        m[0] = 1;
        function<void(int,int)> dfs = [&](int v,int mask){//由于我们只需知道每个字符个数的奇偶性,这里直接用26位的二进制数记录
            for(auto u:graph[v]){
                int bit = 1<<(s[u]-'a');//记录当前字符
                int x = mask^bit;
                res+=m[x];//相同状态的字符串路径,与该路径之间,必然存在一条回文,该回文没有奇数次字符
                for(int i=0;i<26;i++)//满足一个奇数次字符的路径
                    res+=m[x^(1<<i)];
                m[x]++;
                dfs(u,x);
            }
        };
        dfs(0,0);//从初始节点开始,
        return res;
    }
};