HardHash TableBit ManipulationTreeDepth-First SearchUpdated Sep 2026

2791. Count Paths That Can Form a Palindrome in a Tree

Asked at Uber, Goldman Sachs

Difficulty

Hard

Time

O(n * 26)

Space

O(n)

Pattern

Hash Table

Companies

2

Problem

You are given a tree with n nodes numbered 0 to n-1, rooted at node 0. The tree comes as an array parent, where parent[i] is the parent of node i, and parent[0] == -1 because node 0 is the root.

You also get a string s of length n. The character s[i] is written on the edge between node i and its parent. The value s[0] has no edge, so you can ignore it.

Count the number of pairs of nodes (u, v) with u < v such that the characters on the path from u to v can be rearranged into a palindrome. A palindrome reads the same forwards and backwards. Note: you do not need the path itself to be a palindrome — you only need its letters to be rearrangeable into one.

Key rule that decides the answer: a set of letters can be rearranged into a palindrome exactly when at most one letter appears an odd number of times. So for each path you only care about which letters have odd counts, not their order.

Which paths can be rearranged into a palindrome

3s= c140root5s= c2Tree from example 1: parent = [-1,0,0,1,1,2], s ="acaabc"path 3 -> 5acacLetters on the path 3 -> 1 -> 0 -> 2 -> 5 are a, c, a,c.counts: a=2, c=2odd counts: 00 <= 1 -> valid
A path works when at most one letter appears an odd number of times. Path (3,5) gives "acac" — two 'a' and two 'c' — so it works.

Constraints

  • ●n == parent.length == s.length
  • ●1 <= n <= 10^5
  • ●0 <= parent[i] <= n - 1 for all i >= 1
  • ●parent[0] == -1
  • ●parent represents a valid tree
  • ●s consists of only lowercase English letters

Examples

Example 1
Inputparent = [-1,0,0,1,1,2], s = "acaabc"
Output8
WhyThe five parent-child pairs (0,1), (0,2), (1,3), (1,4), (2,5) each have a single letter, so they are valid. Path (2,3) gives "aca", path (1,5) gives "cac", and path (3,5) gives "acac" which can be rearranged into "acca". That is 5 + 3 = 8 valid pairs.
Example 2
Inputparent = [-1,0,0,0,0], s = "aaaaa"
Output10
WhyEvery edge is labeled 'a', so every path is just some number of 'a's. Any such string is a palindrome, so all C(5,2) = 10 pairs of nodes are valid.

Asked At

2 companies
CompanyDifficulty
UberHardView all Uber questions →
Goldman SachsHardView all Goldman Sachs questions →

How to Think About It

1

Key insight: a path forms a palindrome iff at most one character has an odd count. Represent the path as a 26-bit mask (bit i set if character i appears odd times). The path mask from u to v is mask[u] XOR mask[v] XOR (1 << s[root]).

2

Compute masks via DFS from root: mask[root] = 1 << s[root]. For child c of node p: mask[c] = mask[p] ^ (1 << s[c]). The XOR accumulates odd-count flips along the path.

3

Path mask between u and v: mask[u] XOR mask[v]. For a palindrome, popcount(mask[u] XOR mask[v]) <= 1. This means the masks are either equal (0 bits differ) or differ in exactly 1 bit.

4

Count pairs: for each mask value, count pairs of nodes with the same mask (C(cnt,2)) plus pairs differing in exactly 1 bit (cnt[mask] * cnt[mask ^ (1<<i)] for each bit i). Divide cross-bit pairs by 2 to avoid double-counting.

5

Use a hash map to count mask frequencies during DFS. After processing all nodes, iterate the map to count pairs.

Optimal Approach

Step 1: Build adjacency list from parent array.
Step 2: DFS from root to compute mask for each node: mask[child] = mask[parent] XOR (1 << s[child]).
Step 3: Count mask frequencies using a hash map.
Step 4: For each mask in the map:

  • Same-mask pairs: add C(cnt, 2) = cnt*(cnt-1)/2.
  • Cross-bit pairs: for each bit i (0-25), if mask ^ (1<<i) exists in map and mask < mask^(1<<i), add cnt[mask] * cnt[mask^(1<<i)].
    Step 5: Return total.

Walkthrough for n=3, parent=[0,0,0], s="abc":

  • Root=0, mask[0]=1 (a). Children: 1 mask=1^2=3 (b), 2 mask=1^4=5 (c).
  • Masks: {1:1, 3:1, 5:1}. Same-mask: 0 pairs. Cross-bit: 1^3=2 (1 bit) -> 11=1. 1^5=4 (1 bit) -> 11=1. 3^5=6 (2 bits) -> 0. Total: 2.

Time: O(n * 26) for DFS and mask counting. Space: O(n) for masks and hash map.

XOR masks and pair counting

31mask=3 (a,c)40mask=1 (a)52mask=5 (a,c)DFS from the root: mask[child] = mask[parent] XOR (1 <<letter).path mask(u,v) = mask[u] XOR mask[v]valid if popcount <= 1equal masks -> 0 bitsone-bit flip -> 1 bitmask countsmaskcount11325172Same-mask pairs use C(cnt,2); cross-bit pairs use cnt[m] *cnt[m ^ (1<<b)].same mask: C(2,2)+C(2,2) = 2one-bit flips: 1*2 + 1*2 = 4total = 8
Each node stores a 26-bit mask of odd-count letters from the root. Two nodes form a good path when their masks are equal or differ in exactly one bit.
ComplexityTime O(n * 26)Space O(n)The DFS visits each node once, and for each distinct mask we try 26 single-bit flips; the hash map and mask array each hold n entries.

What Trips People Up in Real Interviews

1

Forgetting that the path mask is just mask[u] XOR mask[v], not mask[u] XOR mask[v] XOR something extra. The XOR naturally handles the parity of all characters on the path.

2

Double-counting pairs. Each pair (u,v) should be counted once. When iterating masks, use pairs where mask1 < mask2 for cross-bit pairs, and C(cnt,2) for same-mask pairs.

3

Confusing path with root-to-node. The path between any two nodes u and v goes through their LCA. The XOR trick works regardless of the LCA because XOR cancels out the common prefix.

4

Missing that C(cnt,2) = cnt*(cnt-1)/2 for same-mask pairs. Do not use cnt*cnt which includes self-pairs.

5

Forgetting that single-node paths (u==v) are valid palindromes (1 character). The problem asks for pairs of distinct nodes, so self-pairs are excluded by C(cnt,2).

Solution Code

O(n * 26) time
from collections import defaultdict

class Solution:
    def countPalindromicPaths(self, parent, s):
        n = len(parent)
        g = [[] for _ in range(n)]
        for i in range(1, n):
            g[parent[i]].append(i)
            g[i].append(parent[i])

        mask = [0] * n
        stack = [0]
        mask[0] = 1 << (ord(s[0]) - 97)
        visited = [False] * n
        visited[0] = True
        order = [0]
        while stack:
            u = stack.pop()
            for v in g[u]:
                if not visited[v]:
                    visited[v] = True
                    mask[v] = mask[u] ^ (1 << (ord(s[v]) - 97))
                    stack.append(v)
                    order.append(v)

        cnt = defaultdict(int)
        for m in mask:
            cnt[m] += 1

        ans = 0
        for m, c in cnt.items():
            ans += c * (c - 1) // 2
            for b in range(26):
                t = m ^ (1 << b)
                if t in cnt and m < t:
                    ans += c * cnt[t]
        return ans

Pro at DSA?

Test your skills with a real FAANG-style mock interview.

Start a Mock Interview →

Frequently Asked Questions

What is the Count Paths That Can Form a Palindrome in a Tree problem?

Given a tree with n nodes (0 to n-1), parent array where parent[i] is the parent of node i (0 for root), and a string s of lowercase letters where s[i] is the character at node i. Count the number of unordered pairs of nodes (u,v) such that the path from u to v contains characters that can be rearranged into a palindrome.

How do you solve Count Paths That Can Form a Palindrome in a Tree?

The optimal approach runs in O(n * 26) time and O(n) space. Scroll up to "Optimal Approach" for the step-by-step walkthrough, diagrams, and code in Python, C++ and Java.

What companies ask Count Paths That Can Form a Palindrome in a Tree?

Count Paths That Can Form a Palindrome in a Tree is asked at Uber, Goldman Sachs. It is a hard difficulty problem.

What are common mistakes on Count Paths That Can Form a Palindrome in a Tree?
  • Forgetting that the path mask is just mask[u] XOR mask[v], not mask[u] XOR mask[v] XOR something extra. The XOR naturally handles the parity of all characters on the path.
  • Double-counting pairs. Each pair (u,v) should be counted once. When iterating masks, use pairs where mask1 < mask2 for cross-bit pairs, and C(cnt,2) for same-mask pairs.
  • Confusing path with root-to-node. The path between any two nodes u and v goes through their LCA. The XOR trick works regardless of the LCA because XOR cancels out the common prefix.
  • Missing that C(cnt,2) = cnt*(cnt-1)/2 for same-mask pairs. Do not use cnt*cnt which includes self-pairs.
  • Forgetting that single-node paths (u==v) are valid palindromes (1 character). The problem asks for pairs of distinct nodes, so self-pairs are excluded by C(cnt,2).