DP on Trees Diameter of Tree in DSA C# - Time & Space Complexity
We want to understand how long it takes to find the diameter of a tree using dynamic programming.
The question is: how does the time grow as the tree gets bigger?
Analyze the time complexity of the following code snippet.
// Tree represented as adjacency list
List<int>[] tree = new List<int>[n];
int diameter = 0;
int DFS(int node, int parent) {
int max1 = 0, max2 = 0;
foreach (var child in tree[node]) {
if (child == parent) continue;
int height = DFS(child, node) + 1;
if (height > max1) { max2 = max1; max1 = height; }
else if (height > max2) max2 = height;
}
diameter = Math.Max(diameter, max1 + max2);
return max1;
}
DFS(0, -1); // start DFS from root
This code finds the diameter of a tree by exploring each node once and tracking the longest paths.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: DFS visits each node once and explores its children.
- How many times: Each node and edge is visited exactly once during the DFS traversal.
As the number of nodes grows, the DFS explores each node and its edges once.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 nodes + 9 edges = 19 visits |
| 100 | About 100 nodes + 99 edges = 199 visits |
| 1000 | About 1000 nodes + 999 edges = 1999 visits |
Pattern observation: The operations grow roughly in a straight line with the number of nodes.
Time Complexity: O(n)
This means the time to find the diameter grows linearly with the number of nodes in the tree.
[X] Wrong: "Since we check children inside a loop, the time is O(n²)."
[OK] Correct: Each edge and node is visited only once in total, so the total work is linear, not quadratic.
Understanding this linear time DFS approach is a key skill for tree problems and shows you can handle recursion and dynamic programming on trees efficiently.
"What if the tree was stored as an edge list without adjacency lists? How would that affect the time complexity?"
Practice
Solution
Step 1: Understand the definition of tree diameter
The diameter is the longest path between any two nodes in a tree, not necessarily passing through the root.Step 2: Differentiate diameter from other tree properties
Height is the longest path from root to leaf, number of nodes is size, and sum of values is unrelated to diameter.Final Answer:
The longest path between any two nodes in the tree -> Option BQuick Check:
Diameter = longest path [OK]
- Confusing diameter with height
- Thinking diameter is number of nodes
- Assuming diameter passes through root
Solution
Step 1: Understand adjacency list initialization in C#
For n nodes, create an array of List<int> with size n, then initialize each element with new List<int>().Step 2: Analyze each option
A: var graph = new List<int>[n]; for(int i=0; i(); for(int i=0; iFinal Answer:
var graph = new List<int>[n]; for(int i=0; i -> Option AQuick Check:
Array of lists initialized correctly [OK]
- Not initializing each list element
- Using List<int> without specifying size
- Overwriting array with a single list
using System;
using System.Collections.Generic;
class Program {
static List<int>[] graph;
static int diameter = 0;
static int DFS(int node, int parent) {
int max1 = 0, max2 = 0;
foreach (var child in graph[node]) {
if (child == parent) continue;
int dist = DFS(child, node) + 1;
if (dist > max1) {
max2 = max1;
max1 = dist;
} else if (dist > max2) {
max2 = dist;
}
}
diameter = Math.Max(diameter, max1 + max2);
return max1;
}
static void Main() {
int n = 5;
graph = new List<int>[n];
for (int i = 0; i < n; i++) graph[i] = new List<int>();
graph[0].Add(1); graph[1].Add(0);
graph[1].Add(2); graph[2].Add(1);
graph[1].Add(3); graph[3].Add(1);
graph[3].Add(4); graph[4].Add(3);
DFS(0, -1);
Console.WriteLine(diameter);
}
}Solution
Step 1: Understand the tree structure and DFS traversal
The tree edges are: 0-1, 1-2, 1-3, 3-4. The longest path is from node 2 to node 4 passing through 1 and 3, length 3 edges.Step 2: Trace DFS and diameter calculation
DFS calculates max distances from each node's children. Diameter updates to max sum of two longest child paths. The longest path length is 3.Final Answer:
3 -> Option CQuick Check:
Longest path length = 3 edges [OK]
- Counting nodes instead of edges
- Misunderstanding DFS return values
- Ignoring parent check in DFS
static int DFS(int node, int parent) {
int maxDist = 0;
foreach (var child in graph[node]) {
if (child == parent) continue;
int dist = DFS(child, node) + 1;
if (dist > maxDist) maxDist = dist;
}
diameter = Math.Max(diameter, maxDist);
return maxDist;
}Solution
Step 1: Analyze how diameter is updated
The code tracks only the longest single path from children, ignoring the sum of two longest paths needed for diameter.Step 2: Understand diameter definition
Diameter is the longest path between any two nodes, which may be sum of two longest child paths through current node, not just one.Final Answer:
It only considers the longest single path, missing combined paths for diameter -> Option DQuick Check:
Diameter needs sum of two longest paths [OK]
- Ignoring second longest path
- Forgetting to skip parent node
- Updating diameter inside loop incorrectly
Solution
Step 1: Understand difference between unweighted and weighted trees
In weighted trees, edge lengths vary, so distance must accumulate actual weights, not just count edges.Step 2: Modify DFS to add edge weights
Instead of adding 1 for each edge, add the weight of the edge when calculating distances and updating diameter.Step 3: Ignore incorrect options
Ignoring weights loses accuracy, BFS alone doesn't solve weighted distances, summing all weights is unrelated to diameter.Final Answer:
Replace increments by edge weights when calculating distances in DFS -> Option AQuick Check:
Use edge weights in distance sums [OK]
- Counting edges as 1 ignoring weights
- Using BFS without weight handling
- Summing all weights unrelated to diameter
Ready to prove it?
Pass the test and this pattern moves unknown
