{x}
blog image

Tree Diameter

Solution Explanation: Finding the Diameter of a Tree

This problem asks to find the diameter of a tree, which is the maximum number of edges in any path between two nodes. The solution uses a clever two-pass Depth-First Search (DFS) approach.

Algorithm:

  1. Arbitrary Starting Node: We begin by choosing any node in the tree as a starting point. The choice doesn't affect the final result.

  2. First DFS: Perform a DFS starting from the chosen node. This DFS finds the node that's furthest away from the starting node. Let's call this furthest node node_a. The distance (number of edges) to node_a is recorded.

  3. Second DFS: Now, perform a second DFS, this time starting from node_a. This DFS finds the node furthest away from node_a, let's call it node_b. The distance (number of edges) to node_b represents the diameter of the tree.

Why this works:

The diameter of a tree is always a path between two leaf nodes or between a leaf node and a node with degree 1. The first DFS finds one endpoint of the diameter, and the second DFS finds the other endpoint. The distance between these two endpoints is the diameter.

Time and Space Complexity:

  • Time Complexity: O(N) - Each DFS traversal visits each node and edge exactly once.
  • Space Complexity: O(N) - The space is primarily used for the adjacency list (g in the code) to represent the tree and the recursion stack during the DFS calls. In the worst case, the recursion stack can have a depth of N (a degenerate tree).

Code Explanation (Python):

class Solution:
    def treeDiameter(self, edges: List[List[int]]) -> int:
        def dfs(i: int, fa: int, t: int):
            nonlocal ans, a  # These are modified within the nested function
            for j in g[i]:
                if j != fa:
                    dfs(j, i, t + 1)
            if ans < t:
                ans = t
                a = i
 
        g = defaultdict(list)
        for a, b in edges:
            g[a].append(b)
            g[b].append(a)
        ans = a = 0
        dfs(0, -1, 0)  # First DFS from node 0
        ans = 0       # Reset ans for the second DFS
        dfs(a, -1, 0)  # Second DFS from the furthest node 'a'
        return ans
 

The code first creates an adjacency list g to represent the tree. The dfs function performs the Depth-First Search. ans keeps track of the maximum distance found so far and a stores the node furthest from the starting node. The nonlocal keyword is crucial because it allows the nested function dfs to modify variables in the outer scope. The code runs two DFS calls as described in the algorithm. The final ans will hold the diameter.

The code in other languages (Java, C++, Go, TypeScript) follows the same algorithmic approach, only differing in syntax and data structures. They all achieve the same O(N) time and space complexity.