Problem: 2791. 树中可以形成回文的路径数
思路
由于只有26个字母,可以利用二进制表示,而是否能构成回文串取决于出现奇数频次的字符
解题方法
两个节点V->W的路径的异或之和,相当于V-> LCA, LCA->W,LCA为它们的公共祖先,进而为了方便,V->Root & Root->W的异或之和,由于共同部分可以抵消,因此这样子可以减少计算,只需分别计算Root到各个节点的XOR值,并记录到Map中即可。
Code
class Solution {
private List<int[]>[] g;
private Map<Integer, Integer> cnts;
private long res;
public long countPalindromePaths(List<Integer> parent, String s) {
int n = parent.size();
this.g = new ArrayList[n];
Arrays.setAll(g, k -> new ArrayList<>());
for (int i = 1; i < n; ++i) {
g[parent.get(i)].add(new int[] { i, 1 << (s.charAt(i) - 'a' )});
// g[i][0] 节点, g[i][1] 对应字符
}
this.cnts = new HashMap<>();
dfs(0, 0);
return res;
}
// 统计根节点到每个节点的XOR值
private void dfs(int x, int xor) {
res += cnts.getOrDefault(xor, 0);
// 统计异或值相同的节点
for (int i = 0; i < 26; ++i) {
res += cnts.getOrDefault(xor ^ (1 << i), 0);
}
// 统计异或值为2的整数幂的节点
cnts.put(xor, cnts.getOrDefault(xor, 0) + 1);
// 记录每个异或值得出现频次
for (int[] neighbor : g[x]) {
int y = neighbor[0];
int m = neighbor[1];
dfs(y, xor ^ m); // 从根节点到y的 XOR值
}
}
}