Prerequisites

Before attempting this problem, you should be comfortable with:

  • N-ary Trees - Understanding tree structures where each node can have multiple children
  • Recursion - The solution uses recursive tree traversal to compute heights/depths
  • Tree Height vs Depth - Height is distance down to leaves; depth is distance from root

1. Distance with Height

The height of a node is defined as the length of the longest downward path to a leaf node from that node.

Intuition

The diameter of a tree is the longest path between any two nodes. This path must pass through some node as the highest point (closest to root). At that node, the path goes down through two different children. So the longest path through any node equals the sum of the two largest heights among its children. By computing heights recursively and tracking the maximum path length, we find the diameter.

Algorithm

  1. Define a recursive function that returns the height of a node (longest path to a leaf descendant).
  2. For a leaf node (no children), return height 0.
  3. For each node, track the two largest heights among its children.
  4. As we process each child, update the maximum diameter as the sum of the two largest heights found so far.
  5. Return the largest child height plus 1 as the current node's height.
  6. After traversing the entire tree, return the maximum diameter found.
class Solution:
    def diameter(self, root: 'Node') -> int:
        diameter = 0

        def height(node):
            """ return the height of the node """
            nonlocal diameter

            if len(node.children) == 0:
                return 0

            # select the top two heights
            max_height_1, max_height_2 = 0, 0
            for child in node.children:
                parent_height = height(child) + 1
                if parent_height > max_height_1:
                    max_height_1, max_height_2 = parent_height, max_height_1
                elif parent_height > max_height_2:
                    max_height_2 = parent_height

            # calculate the distance between the two farthest leaves nodes.
            distance = max_height_1 + max_height_2
            diameter = max(diameter, distance)

            return max_height_1

        height(root)
        return diameter

Time & Space Complexity

  • Time complexity: O(N)O(N)
  • Space complexity: O(N)O(N)

Where NN is the number of nodes in the tree.


2. Distance with Depth

The depth of a node is the length of the path to the root node.

Intuition

Instead of tracking heights (distance down to leaves), we can track depths (distance from root). The diameter through a node equals the sum of the two deepest leaf paths minus twice the current node's depth. This accounts for the path going down to one leaf, back up to the current node, and down to another leaf.

Algorithm

  1. Define a recursive function that takes a node and its current depth, returning the maximum depth of any leaf in its subtree.
  2. For a leaf node, return the current depth.
  3. For each node, track the two largest depths found among descendants of its children.
  4. Initialize the first maximum depth with the current depth (handles the case of single-child paths).
  5. Calculate the diameter through this node as: max_depth_1 + max_depth_2 - 2 * current_depth.
  6. Update the global diameter if this path is longer.
  7. Return the maximum depth found to the parent call.
class Solution:
    def diameter(self, root: 'Node') -> int:
        diameter = 0

        def maxDepth(node, curr_depth):
            """ return the maximum depth of leaves nodes
                 descending from the current node
            """
            nonlocal diameter

            if len(node.children) == 0:
                return curr_depth
            
            # select the top 2 depths from its children
            max_depth_1, max_depth_2 = curr_depth, 0
            for child in node.children:
                depth = maxDepth(child, curr_depth+1)
                if depth > max_depth_1:
                    max_depth_1, max_depth_2 = depth, max_depth_1
                elif depth > max_depth_2:
                    max_depth_2 = depth

            # calculate the distance between the two farthest leaves nodes
            distance = max_depth_1 + max_depth_2 - 2 * curr_depth
            diameter = max(diameter, distance)

            return max_depth_1

        maxDepth(root, 0)
        return diameter

Time & Space Complexity

  • Time complexity: O(N)O(N)
  • Space complexity: O(N)O(N)

Where NN is the number of nodes in the tree.


Common Pitfalls

Only Considering Paths Through the Root

A common mistake is assuming the diameter must pass through the root node. The longest path may be entirely within a subtree. You must track the maximum diameter found at any node, not just the root.

# Wrong: Only checking diameter at root level
def diameter(root):
    heights = [height(child) for child in root.children]
    heights.sort(reverse=True)
    return heights[0] + heights[1] if len(heights) >= 2 else 0

# Correct: Track max diameter across all nodes
def diameter(root):
    max_diameter = 0
    def height(node):
        nonlocal max_diameter
        # ... update max_diameter at every node
    height(root)
    return max_diameter

Confusing Height and Depth Definitions

Height (distance down to leaves) and depth (distance from root) are different concepts. Mixing them up leads to incorrect diameter calculations. Height returns the longest path downward from a node, while depth is passed as a parameter representing distance from root.

# Using height: returns longest path DOWN from node
def height(node):
    if not node.children:
        return 0
    return 1 + max(height(child) for child in node.children)

# Using depth: distance FROM ROOT passed as parameter
def maxDepth(node, curr_depth):
    if not node.children:
        return curr_depth  # Returns absolute depth
    return max(maxDepth(child, curr_depth + 1) for child in node.children)

Only Tracking the Single Maximum Height

To compute the diameter through a node, you need the two largest heights among its children. Tracking only the maximum height misses the second-largest, which is needed for the path length calculation.

# Wrong: Only tracking one maximum
max_height = 0
for child in node.children:
    max_height = max(max_height, height(child) + 1)
diameter = max_height  # Missing the second branch!

# Correct: Track top two heights
max_height_1, max_height_2 = 0, 0
for child in node.children:
    h = height(child) + 1
    if h > max_height_1:
        max_height_1, max_height_2 = h, max_height_1
    elif h > max_height_2:
        max_height_2 = h
diameter = max_height_1 + max_height_2