You are given a tree with n
nodes labeled from 0
to n - 1
. Each node has a color represented by an integer in the array colors
of length n
, where colors[i]
is the color of the ith
node.
You are also given a 2D array edges
of size n - 1
, where each edges[i] = [ui, vi]
represents an undirected edge connecting nodes ui
and vi
.
A subtree is considered to be of the same color if all nodes in the subtree have the same color. Return the size of the largest subtree of the same color.
Example 1:
Input: n = 5, colors = [0,1,1,3,0], edges = [[0,1],[0,2],[1,3],[2,4]]
Output: 2
Explanation:
- Subtree 0 contains nodes [0,1,2,3,4] and has colors [0,1,1,3,0], so it is not of the same color.
- Subtree 1 contains nodes [1,3] and has colors [1,3], so it is not of the same color.
- Subtree 2 contains nodes [2,4] and has colors [1,0], so it is not of the same color.
- Subtree 3 contains node [3] and has color [3], so it is of the same color with size 1.
- Subtree 4 contains node [4] and has color [0], so it is of the same color with size 1.
Only subtrees 3 and 4 have the same color (3 and 0, respectively), and their sizes are both 1. Thus, the answer is 1.
Example 2:
Input: n = 5, colors = [0,0,0,0,0], edges = [[0,1],[0,2],[1,3],[2,4]]
Output: 5
Explanation:
Since all nodes have the same color, the subtree containing all the nodes is of the same color, so the answer is 5.
Constraints:
1 <= n <= 105
0 <= colors[i] <= 105
edges.length == n - 1
edges[i].length == 2
0 <= ui, vi < n
edges
represents a valid tree.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force method to find the largest subtree of the same color involves checking every possible subtree. We essentially explore all combinations of nodes and their descendants to see if they form a valid subtree of the desired color. This exhaustive search guarantees that we will find the maximum subtree.
Here's how the algorithm would work step-by-step:
def maximum_subtree_same_color_brute_force(graph, node_colors):
max_subtree_size = 0
for start_node in graph:
# Start a depth-first search from each node
subtree_nodes = [start_node]
subtree_color = node_colors[start_node]
current_subtree_size = 1
max_subtree_size = max(max_subtree_size, current_subtree_size)
nodes_to_explore = [start_node]
while nodes_to_explore:
current_node = nodes_to_explore.pop(0)
for neighbor in graph[current_node]:
# Avoid cycles and only explore same-color neighbors.
if neighbor not in subtree_nodes and node_colors[neighbor] == subtree_color:
subtree_nodes.append(neighbor)
nodes_to_explore.append(neighbor)
current_subtree_size += 1
max_subtree_size = max(max_subtree_size, current_subtree_size)
return max_subtree_size
The most efficient approach involves exploring the tree structure in a specific order to determine the largest possible subtree. We utilize a method where information is passed upwards from the leaves to the root, allowing us to make informed decisions about subtree size.
Here's how the algorithm would work step-by-step:
def maximum_same_color_subtree(node, colors):
max_subtree_size = 0
def dfs(current_node):
nonlocal max_subtree_size
subtree_size = 1
is_same_color = True
for child in current_node.children:
child_subtree_size, child_same_color = dfs(child)
# Propagate color consistency upwards.
if not child_same_color or colors[child.val] != colors[current_node.val]:
is_same_color = False
else:
subtree_size += child_subtree_size
if is_same_color:
# Update max size if the subtree has the same color.
max_subtree_size = max(max_subtree_size, subtree_size)
else:
max_subtree_size = max(max_subtree_size, 1)
return subtree_size, is_same_color
dfs(node)
return max_subtree_size
class Node:
def __init__(self, val):
self.val = val
self.children = []
def create_tree(edges, colors, root_val):
nodes = {}
for i in range(len(colors)):
nodes[i] = Node(i)
root = nodes[root_val]
for parent, child in edges:
nodes[parent].children.append(nodes[child])
return root
# Example Usage (Test case 1)
# colors = [0, 0, 0, 1, 1]
# edges = [[0, 1], [0, 2], [1, 3], [1, 4]]
# root_val = 0
# root = create_tree(edges, colors, root_val)
# result = maximum_same_color_subtree(root, colors)
# print(result) # Output: 3
# Example Usage (Test case 2)
# colors = [0, 1, 0, 1, 1]
# edges = [[0, 1], [0, 2], [1, 3], [1, 4]]
# root_val = 0
# root = create_tree(edges, colors, root_val)
# result = maximum_same_color_subtree(root, colors)
# print(result) # Output 1
# Example Usage (Test case 3)
# colors = [0, 0, 0, 0, 0]
# edges = [[0, 1], [0, 2], [1, 3], [1, 4]]
# root_val = 0
# root = create_tree(edges, colors, root_val)
# result = maximum_same_color_subtree(root, colors)
# print(result) # Output 5
# Example Usage (Test case 4)
# colors = [1,1,1,1,1,0,0,0,0]
# edges = [[0,1],[0,2],[1,3],[1,4],[2,5],[2,6],[5,7],[5,8]]
# root_val = 0
# root = create_tree(edges, colors, root_val)
# result = maximum_same_color_subtree(root, colors)
# print(result) # Output 5
Case | How to Handle |
---|---|
Null or empty tree | Return 0 immediately as there are no nodes to form a subtree. |
Tree with only one node and it matches the target color | Return 1, representing the size of the single-node subtree. |
Tree with only one node and it does not match the target color | Return 0, indicating no valid subtree. |
All nodes in the tree have the target color | Return the total number of nodes in the tree. |
No nodes in the tree have the target color | Return 0, indicating no valid subtree. |
Large tree to ensure the solution is scalable and does not cause stack overflow in recursive solutions | Iterative approaches using stacks or queues can prevent stack overflow for very deep trees; consider using that approach. |
Skewed tree (e.g., a linked list structure) | Handle the skewed structure efficiently without unnecessary traversal of nonexistent branches. |
Target color is negative or zero | The solution must correctly handle any valid integer color value. |