There is an undirected tree with n nodes labeled from 0 to n - 1, and rooted at node 0. You are given a 2D integer array edges of length n - 1, where edges[i] = [ai, bi] indicates that there is an edge between nodes ai and bi in the tree.
A node is good if all the subtrees rooted at its children have the same size.
Return the number of good nodes in the given tree.
A subtree of treeName is a tree consisting of a node in treeName and all of its descendants.
The input is generated such that edges represents a valid tree.
Solutions
Solution 1: DFS
Thinking
A node is good when all of its subtrees have equal size. \(n\le 10^5\) forbids recomputing subtrees at every node. One DFS can compare child sizes on the way back and count the node itself.
\(\textit{dfs}(a,\textit{fa})\) returns the subtree size; \(a\) is good if every child returns the same value. Root an unrooted tree at \(0\). The time is linear.
First, we construct the adjacency list \(\textit{g}\) of the tree based on the given edges \(\textit{edges}\), where \(\textit{g}[a]\) represents all the neighboring nodes of node \(a\).
Next, we design a function \(\textit{dfs}(a, \textit{fa})\) to calculate the number of nodes in the subtree rooted at node \(a\) and to accumulate the count of good nodes. Here, \(\textit{fa}\) represents the parent node of node \(a\).
The execution process of the function \(\textit{dfs}(a, \textit{fa})\) is as follows:
Initialize variables \(\textit{pre} = -1\), \(\textit{cnt} = 1\), \(\textit{ok} = 1\), representing the number of nodes in a subtree of node \(a\), the total number of nodes in all subtrees of node \(a\), and whether node \(a\) is a good node, respectively.
Traverse all neighboring nodes \(b\) of node \(a\). If \(b\) is not equal to \(\textit{fa}\), recursively call \(\textit{dfs}(b, a)\), with the return value being \(\textit{cur}\), and add \(\textit{cur}\) to \(\textit{cnt}\). If \(\textit{pre} < 0\), assign \(\textit{cur}\) to \(\textit{pre}\); otherwise, if \(\textit{pre}\) is not equal to \(\textit{cur}\), it means the number of nodes in different subtrees of node \(a\) is different, and set \(\textit{ok}\) to \(0\).
Finally, add \(\textit{ok}\) to the answer and return \(\textit{cnt}\).
In the main function, we call \(\textit{dfs}(0, -1)\) and return the final answer.
The time complexity is \(O(n)\), and the space complexity is \(O(n)\). Here, \(n\) represents the number of nodes.
A node is good when every child subtree has the same size. \(n\) can reach \(10^5\), so recomputing subtrees at every node is quadratic. On a chain the first recursive call always follows the only child, so the depth is \(n\) and exceeds the default recursion limit.
A subtree size is known only after every child has been finished.
An explicit stack walks the tree in postorder. On entry, push the exit marker and then the children. On exit, read each child's subtree size. If those sizes match, the current node is good, and its own subtree size is stored. The unrooted tree is rooted at \(0\).
First, we construct the adjacency list \(\textit{g}\) of the tree based on the given edges \(\textit{edges}\), where \(\textit{g}[a]\) represents all the neighboring nodes of node \(a\).
An explicit stack walks the tree from node \(0\) in postorder. Entering a node pushes that node's exit marker and then its children, so the children finish first. On exit, each child's subtree size is already stored. Initialize \(\textit{pre} = -1\), \(\textit{cnt} = 1\), and \(\textit{ok} = 1\). For each child, add its subtree size to \(\textit{cnt}\). If that size differs from \(\textit{pre}\), set \(\textit{ok}\) to \(0\). Then add \(\textit{ok}\) to the answer and store \(\textit{cnt}\) as the current node's subtree size.
The time complexity is \(O(n)\), and the space complexity is \(O(n)\). Here, \(n\) represents the number of nodes.