Given a tree (i.e., a connected, undirected graph that has no cycles) consisting of n nodes numbered from 0 to n - 1 and exactly n - 1 edges. The diameter of a tree is the length of the longest path between any two nodes in the tree.
Return the diameter of the tree.
Example 1:
Input: edges = [[0,1],[0,2]] Output: 2 Explanation: A longest path of the tree is the path 1 - 0 - 2.
Example 2:
Input: edges = [[0,1],[1,2],[2,3],[1,4],[4,5]] Output: 4 Explanation: A longest path of the tree is the path 3 - 2 - 1 - 4 - 5.
Constraints:
n == edges.length + 11 <= n <= 1040 <= edges[i][0], edges[i][1] < nWhen 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:
To find the longest path in a tree using the brute force approach, we'll explore every possible path between every pair of nodes in the tree. This means checking each possible start and end point. We'll then see which path is the longest.
Here's how the algorithm would work step-by-step:
def tree_diameter_brute_force(graph):
all_nodes = list(graph.keys())
number_of_nodes = len(all_nodes)
longest_path = 0
for start_node_index in range(number_of_nodes):
for end_node_index in range(start_node_index + 1, number_of_nodes):
start_node = all_nodes[start_node_index]
end_node = all_nodes[end_node_index]
# Find the path between the two nodes.
path = find_path(graph, start_node, end_node)
# Measure the length of the path.
if path:
path_length = len(path) - 1
# Keep track of the longest path.
longest_path = max(longest_path, path_length)
return longest_path
def find_path(graph, start_node, end_node):
queue = [(start_node, [start_node])]
visited = set()
while queue:
(current_node, path) = queue.pop(0)
if current_node == end_node:
return path
visited.add(current_node)
for neighbor in graph[current_node]:
if neighbor not in visited:
queue.append((neighbor, path + [neighbor]))
return NoneThe tree diameter problem aims to find the longest path between any two nodes in a tree. The optimal approach cleverly avoids checking every possible path by using a depth-first search strategy to find the farthest node from an arbitrary starting point, and then repeats the process from that farthest node.
Here's how the algorithm would work step-by-step:
def tree_diameter(graph):
def depth_first_search(start_node):
visited = {}
max_distance = 0
farthest_node = start_node
stack = [(start_node, 0)]
visited[start_node] = True
while stack:
node, distance = stack.pop()
if distance > max_distance:
max_distance = distance
farthest_node = node
for neighbor in graph[node]:
if neighbor not in visited:
visited[neighbor] = True
stack.append((neighbor, distance + 1))
return farthest_node
# Find the farthest node from an arbitrary starting node.
arbitrary_node = next(iter(graph))
farthest_node_one = depth_first_search(arbitrary_node)
# Find the farthest node from the first farthest node.
farthest_node_two = depth_first_search(farthest_node_one)
# Calculating diameter using two dfs calls.
visited = {}
stack = [(farthest_node_one, 0)]
visited[farthest_node_one] = True
max_diameter = 0
while stack:
node, distance = stack.pop()
if node == farthest_node_two:
max_diameter = distance
break
for neighbor in graph[node]:
if neighbor not in visited:
visited[neighbor] = True
stack.append((neighbor, distance + 1))
return max_diameter| Case | How to Handle |
|---|---|
| Null or empty tree | Return 0 as the diameter of an empty tree is defined as zero. |
| Tree with only one node | Return 0 as the diameter of a single node tree is zero. |
| Tree with only two nodes | Return 1 as the diameter is the single edge connecting the two nodes. |
| Skewed tree (all nodes in a single branch) | The algorithm should correctly calculate the longest path through the skewed tree. |
| Complete binary tree | Ensure the algorithm correctly handles balanced trees and calculates the diameter which goes through the root. |
| Large tree to check for stack overflow with recursion | Consider iterative approach if the recursion depth becomes a bottleneck. |
| Tree with negative node values (although node values are irrelevant) | The algorithm works correctly with negative node values as only the structure of the tree matters. |
| Integer overflow if the depth is too large. | Use a data type with larger capacity (e.g. long) to store the diameter if required to prevent integer overflow. |