You are given a n-ary tree of depth n
. Each node has a unique value from 1
to n
.
You are also given a list of n - 1
Edges
. Each Edge
contains the values of two different nodes. Your task is to find the root of the n-ary tree.
Example:
Input: edges = [[1,2],[1,3],[1,4],[1,5],[2,6],[2,7]]
Output: 1
Explanation:
Given the edges:
The root of the tree is the node with value 1 since it doesn't have any parent.
Follow up:
Can you find the root in O(n)
time and O(1)
space?
Constraints:
n == edges.length + 1
1 <= n <= 105
1 <= Node.val <= n
Node.val
is unique.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:
We have a tree where each node can have many children, and we need to find the very top node, which we call the root. The brute force way is to check every node to see if it could be the root, by seeing if anyone claims it as their child.
Here's how the algorithm would work step-by-step:
class Node:
def __init__(self, val):
self.val = val
self.children = []
def find_root_brute_force(nodes):
possible_roots = []
for current_node in nodes:
is_child = False
for other_node in nodes:
if current_node != other_node:
if current_node in other_node.children:
is_child = True
break
# Only add node to possible roots if no parent
if not is_child:
possible_roots.append(current_node)
# Ensures that the edge cases work correctly
if len(possible_roots) == 1:
return possible_roots[0]
elif len(possible_roots) > 0:
return possible_roots[0]
return None
The key is to realize that every node in the tree, except the root, is pointed to by its parent. We can use this fact to quickly identify the root. By summing all node values and subtracting the sums of all child node values, the remaining value will correspond to the root node's value.
Here's how the algorithm would work step-by-step:
class Node:
def __init__(self, val):
self.val = val
self.children = []
def find_root(tree_nodes):
all_nodes_sum = 0
children_nodes_sum = 0
# Calculate the sum of all nodes.
for node in tree_nodes:
all_nodes_sum += node.val
# Calculate sum of all children nodes.
for node in tree_nodes:
for child in node.children:
children_nodes_sum += child.val
# The difference isolates the root node's value.
root_value = all_nodes_sum - children_nodes_sum
# Find the node with value equal to the difference.
for node in tree_nodes:
if node.val == root_value:
root_node = node
return root_node
return None
Case | How to Handle |
---|---|
Null or empty list of nodes | Return null/None, indicating an empty tree has no root. |
Single node in the list | Return that single node as it is the root. |
All nodes are the same object (same memory address) | The algorithm must not rely on node equality for comparison and should return the correct root node (if it exists). |
Maximum number of nodes, potential memory issues | Ensure the solution uses memory efficiently and avoid creating unnecessary copies of the nodes. |
The N-ary tree is disconnected, resulting in no root being identified | If no node has an indegree of zero, return null to indicate no single root exists. |
Cycles exist within the N-ary tree structure | The indegree approach will still function properly as it's based on node references, not the paths. |
Integer overflow in indegree calculations (if using integer counters) | Use a data type with sufficient range (e.g., long) to prevent overflow or use alternative approach that avoid indegree count. |
Input list contains null nodes | Handle null nodes gracefully, skipping them in the processing to prevent NullPointerExceptions. |