{x}
blog image

Count Nodes With the Highest Score

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:

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:

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.

Solution Explanation: Counting Nodes with the Highest Score

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:

  1. Tree Construction: The input parents array represents the tree structure. We build an adjacency list (graph) g to efficiently access children of each node.

  2. 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.

  3. 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.
    • The DFS recursively explores the children of i. For each child j (excluding the parent fa to avoid cycles), it recursively calls dfs(j, i).
    • The return value of the recursive call (t) represents the size of the subtree rooted at child j. This t is multiplied into the score and added to cnt.
    • After processing all children, if there are remaining nodes in the original tree (n - cnt > 0), this represents a subtree resulting from removing node i, and its size is multiplied into score.
  4. Tracking Highest Score:

    • mx: Stores the current highest score encountered.
    • ans: Counts the number of nodes with the highest score.
    • After calculating 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.
  5. 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.