
Input: parent =[-1,0,0,1,1,2], s ="acaabc"Output: 8Explanation: The valid pairs are:- All the pairs(0,1),(0,2),(1,3),(1,4) and (2,5) result in one character which is always a palindrome.- The pair(2,3) result in the string "aca" which is a palindrome.- The pair(1,5) result in the string "cac" which is a palindrome.- The pair(3,5) result in the string "acac" which can be rearranged into the palindrome "acca".
A path can be rearranged into a palindrome if at most one character has an odd count. We can represent the parity of character counts along the path from the root to each node as a bitmask. For each node, the XOR of the bitmasks of two nodes gives the parity of the path between them. If the XOR result has at most one bit set, the path can form a palindrome.
classSolution {
funcountPalindromePaths(parent: IntArray, s: String): Long {
val n = parent.size
val g = Array(n) { mutableListOf<Int>() }
for (i in1 until n) g[parent[i]].add(i)
val freq = mutableMapOf<Int, Int>()
fundfs(u: Int, mask: Int) {
val m = mask xor (1 shl (s[u] - 'a'))
freq[m] = freq.getOrDefault(m, 0) + 1for (v in g[u]) dfs(v, m)
}
dfs(0, 0)
var ans = 0Lfor ((mask, cnt) in freq) {
ans += cnt.toLong() * (cnt - 1) / 2for (i in0 until 26) {
val m2 = mask xor (1 shl i)
freq[m2]?.let { ans += cnt.toLong() * it / 2 }
}
}
return ans
}
}
classSolution:
defcountPalindromePaths(self, parent: list[int], s: str) -> int:
from collections import defaultdict
n = len(parent)
g = [[] for _ in range(n)]
for i in range(1, n):
g[parent[i]].append(i)
freq = defaultdict(int)
defdfs(u: int, mask: int):
mask ^=1<< (ord(s[u]) - ord('a'))
freq[mask] +=1for v in g[u]:
dfs(v, mask)
dfs(0, 0)
ans =0for mask, cnt in freq.items():
ans += cnt * (cnt -1) //2for i in range(26):
m2 = mask ^ (1<< i)
if m2 in freq:
ans += cnt * freq[m2] //2return ans