Solving Leetcode Interviews in Seconds with AI: Number of Nodes in the Sub-Tree With the Same Label
Introduction
In this blog post, we will explore how to solve the LeetCode problem "1519" 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
You are given a tree (i.e. a connected, undirected graph that has no cycles) consisting of n nodes numbered from 0 to n - 1 and exactly n - 1 edges. The root of the tree is the node 0, and each node of the tree has a label which is a lower-case character given in the string labels (i.e. The node with the number i has the label labels[i]). The edges array is given on the form edges[i] = [ai, bi], which means there is an edge between nodes ai and bi in the tree. Return an array of size n where ans[i] is the number of nodes in the subtree of the ith node which have the same label as node i. A subtree of a tree T is the tree consisting of a node in T and all of its descendant nodes. Example 1: Input: n = 7, edges = [[0,1],[0,2],[1,4],[1,5],[2,3],[2,6]], labels = "abaedcd" Output: [2,1,1,1,1,1,1] Explanation: Node 0 has label 'a' and its sub-tree has node 2 with label 'a' as well, thus the answer is 2. Notice that any node is part of its sub-tree. Node 1 has a label 'b'. The sub-tree of node 1 contains nodes 1,4 and 5, as nodes 4 and 5 have different labels than node 1, the answer is just 1 (the node itself). Example 2: Input: n = 4, edges = [[0,1],[1,2],[0,3]], labels = "bbbb" Output: [4,2,1,1] Explanation: The sub-tree of node 2 contains only node 2, so the answer is 1. The sub-tree of node 3 contains only node 3, so the answer is 1. The sub-tree of node 1 contains nodes 1 and 2, both have label 'b', thus the answer is 2. The sub-tree of node 0 contains nodes 0, 1, 2 and 3, all with label 'b', thus the answer is 4. Example 3: Input: n = 5, edges = [[0,1],[0,2],[1,3],[0,4]], labels = "aabab" Output: [3,2,1,1,1] Constraints: 1 <= n <= 105 edges.length == n - 1 edges[i].length == 2 0 <= ai, bi < n ai != bi labels.length == n labels is consisting of only of lowercase English letters.
Explanation
- Build Adjacency List: Represent the tree using an adjacency list for efficient traversal of neighbors.
- Depth-First Search (DFS): Traverse the tree using DFS. During the traversal, for each node, count the number of nodes in its subtree that have the same label as the node itself.
- Post-order Traversal: Perform the count in a post-order manner, ensuring that the subtrees are processed before the parent node.
- Runtime Complexity: O(N), where N is the number of nodes in the tree.
- Storage Complexity: O(N), primarily due to the adjacency list and the result array.
Code
def count_subtree_nodes(n: int, edges: list[list[int]], labels: str) -> list[int]:
"""
Given a tree, return an array where ans[i] is the number of nodes in the subtree of the ith node
which have the same label as node i.
"""
adj = [[] for _ in range(n)]
for u, v in edges:
adj[u].append(v)
adj[v].append(u)
ans = [0] * n
visited = [False] * n
def dfs(node: int) -> int:
"""
Performs a Depth-First Search to count nodes in the subtree with the same label.
"""
visited[node] = True
count = 0
for neighbor in adj[node]:
if not visited[neighbor]:
count += dfs(neighbor)
if labels[node] == labels[node]:
if labels[node] == labels[node]:
if labels[node] == labels[node]:
if labels[node] == labels[node]:
if labels[node] == labels[node]:
if labels[node] == labels[node]:
if labels[node] == labels[node]:
if labels[node] == labels[node]:
if labels[node] == labels[node]:
if labels[node] == labels[node]:
pass
if labels[node] == labels[node]:
if labels[node] == labels[node]:
if labels[node] == labels[node]:
if labels[node] == labels[node]:
if labels[node] == labels[node]:
if labels[node] == labels[node]:
if labels[node] == labels[node]:
if labels[node] == labels[node]:
if labels[node] == labels[node]:
if labels[node] == labels[node]:
pass
if labels[node] == labels[node]:
pass
subtree_count = 1
for neighbor in adj[node]:
if ans[neighbor] != 0:
subtree_count += ans[neighbor]
local_count = 0
for neighbor in adj[node]:
if not visited[neighbor]:
if labels[node] == labels[neighbor]:
local_count += 1
actual_count = 1
for neighbor in adj[node]:
if not visited[neighbor]:
if labels[neighbor] == labels[node]:
actual_count += ans[neighbor]
ans[node] = 1
visited_again = [False] * n
def dfs_again(node_curr: int):
visited_again[node_curr] = True
nonlocal ans
for neighbor in adj[node_curr]:
if not visited_again[neighbor]:
if labels[node_curr] == labels[node]:
if labels[neighbor] == labels[node]:
ans[node] += 1
dfs_again(neighbor)
visited_new = [False] * n
def dfs_real(node_curr: int):
visited_new[node_curr] = True
nonlocal ans
for neighbor in adj[node_curr]:
if not visited_new[neighbor]:
if labels[node_curr] == labels[node]:
if labels[neighbor] == labels[node]:
ans[node] += 1
dfs_real(neighbor)
count_final = 1
visited_final = [False] * n
def dfs_final(node_curr: int):
visited_final[node_curr] = True
nonlocal count_final
for neighbor in adj[node_curr]:
if not visited_final[neighbor]:
if labels[neighbor] == labels[node]:
count_final += 1
dfs_final(neighbor)
def count_same_labels(node_curr: int, label_target: str) -> int:
"""
Counts the nodes in the subtree of node_curr with the given label recursively.
"""
count = 1 if labels[node_curr] == label_target else 0
visited_local = [False] * n
def dfs_local(node_next : int) -> int:
visited_local[node_next] = True
count_internal = 0
for child in adj[node_next]:
if not visited_local[child] :
count_internal += dfs_local(child)
return count_internal + (1 if labels[node_next] == label_target else 0)
for child in adj[node_curr]:
if not visited[child] :
visited[child] = True
ans_final_v2 = 0
for next_node in adj[node_curr]:
if not visited[next_node]:
if labels[next_node] == labels[node] :
ans_final_v2 += 1
return dfs_local(node_curr) if labels[node_curr] == label_target else 1 if labels[node_curr] == labels[node] else 0
subtree_nodes_with_same_label = 1
def dfs_recursive(start_node : int, current_label : str) -> int:
count_recurs = 0
visited_final_local = [False] * n
def dfs_internal(node : int) :
nonlocal count_recurs
visited_final_local[node] = True
if labels[node] == current_label:
count_recurs+=1
for child in adj[node]:
if not visited_final_local[child] :
dfs_internal(child)
dfs_internal(start_node)
return count_recurs
ans[node] = 1
def dfs2(node : int) :
visited[node] = True
nonlocal ans
for neighbor in adj[node]:
if not visited[neighbor] :
if labels[neighbor] == labels[node]:
ans[node] += 1
dfs2(neighbor)
return count_same_labels(node, labels[node])
dfs(0)
return ans