Skip to main content

Command Palette

Search for a command to run...

Solving Leetcode Interviews in Seconds with AI: Number of Nodes in the Sub-Tree With the Same Label

Updated
5 min read

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

More from this blog

C

Chatmagic blog

2894 posts

Solving Leetcode Interviews in Seconds with AI: Number of Nodes in the Sub-Tree With the Same Label