There is a binary tree rooted at 0
consisting of n
nodes. The nodes are labeled from 0
to n - 1
. You are given a 0-indexed integer array parents
representing the tree, where parents[i]
is the parent of node i
. Since node 0
is the root, parents[0] == -1
.
Each node has a score. To find the score of a node, consider if the node and the edges connected to it were removed. The tree would become one or more non-empty subtrees. The size of a subtree is the number of the nodes in it. The score of the node is the product of the sizes of all those subtrees.
Return the number of nodes that have the highest score.
Example 1:
Input: parents = [-1,2,0,2,0] Output: 3 Explanation: - The score of node 0 is: 3 * 1 = 3 - The score of node 1 is: 4 = 4 - The score of node 2 is: 1 * 1 * 2 = 2 - The score of node 3 is: 4 = 4 - The score of node 4 is: 4 = 4 The highest score is 4, and three nodes (node 1, node 3, and node 4) have the highest score.
Example 2:
Input: parents = [-1,2,0] Output: 2 Explanation: - The score of node 0 is: 2 = 2 - The score of node 1 is: 2 = 2 - The score of node 2 is: 1 * 1 = 1 The highest score is 2, and two nodes (node 0 and node 1) have the highest score.
Constraints:
n == parents.length
2 <= n <= 105
parents[0] == -1
0 <= parents[i] <= n - 1
for i != 0
parents
represents a valid binary tree.This problem involves traversing a tree to calculate scores for each node and then finding the number of nodes with the highest score. The score of a node is calculated by removing the node and its connecting edges, resulting in one or more subtrees. The score is the product of the sizes of these subtrees.
Algorithm:
Tree Construction: The input parents
array represents the tree structure. We build an adjacency list (graph) g
to efficiently access children of each node.
Depth-First Search (DFS): A recursive DFS function dfs(i, fa)
is the core of the solution. It takes the current node i
and its parent fa
as input.
Score Calculation within DFS:
cnt
: Tracks the size of the subtree rooted at the current node i
. It's initialized to 1 (the node itself).score
: Keeps track of the product of subtree sizes. It's initialized to 1.i
. For each child j
(excluding the parent fa
to avoid cycles), it recursively calls dfs(j, i)
.t
) represents the size of the subtree rooted at child j
. This t
is multiplied into the score
and added to cnt
.n - cnt > 0
), this represents a subtree resulting from removing node i
, and its size is multiplied into score
.Tracking Highest Score:
mx
: Stores the current highest score encountered.ans
: Counts the number of nodes with the highest score.score
for node i
, it's compared with mx
. If score > mx
, mx
is updated, and ans
is set to 1. If score == mx
, ans
is incremented.Return Value: The function returns ans
, which is the number of nodes with the highest score.
Time Complexity: O(N), where N is the number of nodes. The DFS visits each node exactly once.
Space Complexity: O(N). The space is dominated by the adjacency list g
and the recursive call stack during DFS. In the worst case (a skewed tree), the stack depth can be O(N).
Code Examples (Python):
class Solution:
def countHighestScoreNodes(self, parents: List[int]) -> int:
n = len(parents)
g = [[] for _ in range(n)]
for i in range(1, n):
g[parents[i]].append(i)
ans = mx = 0
def dfs(i, fa):
nonlocal ans, mx
cnt = score = 1
for j in g[i]:
if j != fa:
t = dfs(j, i)
score *= t
cnt += t
if n - cnt > 0:
score *= n - cnt
if mx < score:
mx = score
ans = 1
elif mx == score:
ans += 1
return cnt
dfs(0, -1)
return ans
The code in other languages follows the same logic, with minor syntactic differences. The provided code examples in Java, C++, Go, TypeScript, and C# all implement this efficient DFS-based approach.