Solving Leetcode Interviews in Seconds with AI: Count the Number of Good Nodes
Introduction
In this blog post, we will explore how to solve the LeetCode problem "3249" using AI. LeetCode is a popular platform for preparing for coding interviews, and with the help of AI tools like Chatmagic, we can generate solutions quickly and efficiently - helping you pass the interviews and get the job offer without having to study for months.
Problem Statement
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. Example 1: Input: edges = [[0,1],[0,2],[1,3],[1,4],[2,5],[2,6]] Output: 7 Explanation: All of the nodes of the given tree are good. Example 2: Input: edges = [[0,1],[1,2],[2,3],[3,4],[0,5],[1,6],[2,7],[3,8]] Output: 6 Explanation: There are 6 good nodes in the given tree. They are colored in the image above. Example 3: Input: edges = [[0,1],[1,2],[1,3],[1,4],[0,5],[5,6],[6,7],[7,8],[0,9],[9,10],[9,12],[10,11]] Output: 12 Explanation: All nodes except node 9 are good. Constraints: 2 <= n <= 105 edges.length == n - 1 edges[i].length == 2 0 <= ai, bi < n The input is generated such that edges represents a valid tree.
Explanation
- Tree Traversal and Subtree Size Calculation: Perform a Depth-First Search (DFS) to traverse the tree. During the traversal, calculate the size of each subtree rooted at each node. The size of a subtree is the number of nodes in that subtree (including the root).
- Good Node Identification: After calculating the subtree sizes, iterate through the nodes. For each node, check if all its children have the same subtree size. If they do, increment the count of good nodes.
- Rooted Tree Representation: Use an adjacency list to represent the tree's structure based on the given edges. This facilitates efficient traversal of children for each node.
- Runtime Complexity: O(N), where N is the number of nodes. Storage Complexity: O(N)
Code
def count_good_nodes(edges):
"""
Counts the number of good nodes in a tree.
Args:
edges: A list of tuples representing the edges of the tree.
Returns:
The number of good nodes in the tree.
"""
n = len(edges) + 1
adj = [[] for _ in range(n)]
for u, v in edges:
adj[u].append(v)
adj[v].append(u)
subtree_sizes = [0] * n
good_nodes_count = 0
def dfs(node, parent):
"""
Performs a Depth-First Search to calculate subtree sizes.
Args:
node: The current node being visited.
parent: The parent of the current node.
Returns:
The size of the subtree rooted at the current node.
"""
subtree_sizes[node] = 1
for child in adj[node]:
if child != parent:
subtree_sizes[node] += dfs(child, node)
return subtree_sizes[node]
dfs(0, -1) # Start DFS from the root (node 0)
for node in range(n):
is_good = True
first_child_size = -1
for child in adj[node]:
if any(edges_list for edges_list in edges if node in edges_list and child in edges_list):
# Find the edge that connects node and child
is_direct_child = False
for u, v in edges:
if (u == node and v == child) or (u == child and v == node):
is_direct_child = True
break
if not is_direct_child:
continue # Skip if child is actually parent
if first_child_size == -1:
first_child_size = subtree_sizes[child]
elif subtree_sizes[child] != first_child_size:
is_good = False
break # Optimization: No need to check further children
if is_good:
good_nodes_count += 1
return good_nodes_count