You are given the root of an N-ary tree. An N-ary tree is a tree in which each node can have zero or more children (not limited to two as in binary trees). Your task is to compute the diameter of the tree.
The diameter of an N-ary tree is defined as the length of the longest path between any two nodes in the tree. The path may or may not pass through the root. The length of a path is measured as the number of edges between the two nodes.
root
.Constraints:
[1, 10^4]
.children
list is not null (may be empty).To solve this problem, let's first understand what the diameter means in the context of an N-ary tree. Unlike binary trees, each node can have many children, so the branching factor is not fixed. The diameter is the longest path (in terms of edges) between any two nodes, which may or may not pass through the root.
A brute-force approach would be to compute the longest path between every pair of nodes, but this would be extremely inefficient for large trees. Instead, we can use a recursive approach similar to how we find the diameter in binary trees, but generalized for N-ary trees.
The key insight is that the diameter at a node can be the sum of the two largest heights among its children, because the longest path passing through that node would go down to the deepest two children (possibly different subtrees). So, for each node, we want to track the two largest subtree heights among its children.
We use a depth-first search (DFS) traversal to process the tree from the bottom up. For each node, we:
max1
and max2
.max1 + max2
if it's greater than the current best.max1 + 1
as the height of the current node (since we add one edge to reach the child).This way, we ensure that at every node, we consider the possibility that the longest path may pass through that node, connecting its two deepest subtrees. We use a variable (often nonlocal or class-level) to keep track of the maximum diameter found so far.
Consider the following N-ary tree:
1 / | \ 2 3 4 | \ 5 6
Let's compute the heights:
Brute-force approach:
The diameter of an N-ary tree can be efficiently computed using a single DFS traversal. By keeping track of the two largest subtree heights at each node, we can update the maximum possible diameter as we traverse the tree. This approach is elegant because it generalizes the binary tree diameter method, operates in linear time, and uses only a small amount of extra space. Understanding how the diameter relates to the sum of the two largest child heights at each node is the key insight.
# Definition for a Node.
class Node:
def __init__(self, val=None, children=None):
self.val = val
self.children = children if children is not None else []
class Solution:
def diameter(self, root: 'Node') -> int:
self.max_diameter = 0
def dfs(node):
if not node:
return 0
max1, max2 = 0, 0 # The two largest heights among children
for child in node.children:
h = dfs(child)
if h > max1:
max2 = max1
max1 = h
elif h > max2:
max2 = h
# Update the diameter at this node
self.max_diameter = max(self.max_diameter, max1 + max2)
return max1 + 1 # Height of this node
dfs(root)
return self.max_diameter
/*
// Definition for a Node.
class Node {
public:
int val;
vector<Node*> children;
Node() {}
Node(int _val) {
val = _val;
}
Node(int _val, vector<Node*> _children) {
val = _val;
children = _children;
}
};
*/
class Solution {
public:
int maxDiameter = 0;
int dfs(Node* node) {
if (!node) return 0;
int max1 = 0, max2 = 0;
for (Node* child : node->children) {
int h = dfs(child);
if (h > max1) {
max2 = max1;
max1 = h;
} else if (h > max2) {
max2 = h;
}
}
maxDiameter = max(maxDiameter, max1 + max2);
return max1 + 1;
}
int diameter(Node* root) {
dfs(root);
return maxDiameter;
}
};
/*
// Definition for a Node.
class Node {
public int val;
public List<Node> children;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, List<Node> _children) {
val = _val;
children = _children;
}
};
*/
class Solution {
private int maxDiameter = 0;
private int dfs(Node node) {
if (node == null) return 0;
int max1 = 0, max2 = 0;
for (Node child : node.children) {
int h = dfs(child);
if (h > max1) {
max2 = max1;
max1 = h;
} else if (h > max2) {
max2 = h;
}
}
maxDiameter = Math.max(maxDiameter, max1 + max2);
return max1 + 1;
}
public int diameter(Node root) {
dfs(root);
return maxDiameter;
}
}
/**
* // Definition for a Node.
* function Node(val, children) {
* this.val = val;
* this.children = children || [];
* };
*/
/**
* @param {Node} root
* @return {number}
*/
var diameter = function(root) {
let maxDiameter = 0;
function dfs(node) {
if (!node) return 0;
let max1 = 0, max2 = 0;
for (let child of node.children) {
let h = dfs(child);
if (h > max1) {
max2 = max1;
max1 = h;
} else if (h > max2) {
max2 = h;
}
}
maxDiameter = Math.max(maxDiameter, max1 + max2);
return max1 + 1;
}
dfs(root);
return maxDiameter;
};