Diameter of Binary Tree in DSA Go - Time & Space Complexity
We want to understand how the time needed to find the diameter of a binary tree changes as the tree grows.
The question is: how does the number of steps grow when the tree has more nodes?
Analyze the time complexity of the following code snippet.
func diameterOfBinaryTree(root *TreeNode) int {
maxDiameter := 0
var depth func(node *TreeNode) int
depth = func(node *TreeNode) int {
if node == nil {
return 0
}
left := depth(node.Left)
right := depth(node.Right)
if left+right > maxDiameter {
maxDiameter = left + right
}
if left > right {
return left + 1
}
return right + 1
}
depth(root)
return maxDiameter
}
This code finds the longest path between any two nodes in a binary tree by calculating depths recursively.
- Primary operation: Recursive calls to visit each node once.
- How many times: Each node is visited exactly one time.
As the number of nodes (n) increases, the function visits each node once to calculate depths.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 recursive calls |
| 100 | About 100 recursive calls |
| 1000 | About 1000 recursive calls |
Pattern observation: The number of operations grows roughly in direct proportion to 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: "The function visits nodes multiple times, so time is more than linear."
[OK] Correct: Each node is visited once during the depth calculation, so the total work is proportional to the number of nodes.
Understanding this linear time complexity helps you explain efficient tree traversal and recursion in interviews confidently.
"What if the tree was skewed (like a linked list)? How would the time complexity change?"
Practice
Solution
Step 1: Understand the diameter definition
The diameter is the longest path between any two nodes, which may or may not pass through the root.Step 2: Differentiate from other tree properties
Height is the longest path from root to leaf, number of nodes counts all nodes, leaves count only leaf nodes.Final Answer:
The length of the longest path between any two nodes in the tree -> Option AQuick Check:
Diameter = longest path between nodes [OK]
- Confusing diameter with height
- Thinking diameter counts nodes instead of edges
- Assuming diameter must pass through root
Solution
Step 1: Identify correct parameter type
The function should accept a pointer to TreeNode to handle nil nodes and avoid copying.Step 2: Identify correct return type
Height is an integer value representing depth, so return type must be int.Final Answer:
func height(node *TreeNode) int -> Option BQuick Check:
Pointer input and int output for height [OK]
- Using value receiver instead of pointer
- Returning wrong type like string or bool
- Passing int instead of TreeNode pointer
type TreeNode struct {
Val int
Left *TreeNode
Right *TreeNode
}
root := &TreeNode{Val: 1}
root.Left = &TreeNode{Val: 2}
root.Right = &TreeNode{Val: 3}
root.Left.Left = &TreeNode{Val: 4}
root.Left.Right = &TreeNode{Val: 5}
// Diameter function uses height helper internally
func diameterOfBinaryTree(root *TreeNode) int {
maxDiameter := 0
var height func(node *TreeNode) int
height = func(node *TreeNode) int {
if node == nil {
return 0
}
leftHeight := height(node.Left)
rightHeight := height(node.Right)
if leftHeight+rightHeight > maxDiameter {
maxDiameter = leftHeight + rightHeight
}
if leftHeight > rightHeight {
return leftHeight + 1
}
return rightHeight + 1
}
height(root)
return maxDiameter
}
fmt.Println(diameterOfBinaryTree(root))Solution
Step 1: Calculate heights of subtrees
Left subtree of root has height 2 (nodes 2->4 or 2->5), right subtree height is 1 (node 3).Step 2: Calculate diameter as sum of left and right heights
Diameter = leftHeight + rightHeight = 2 + 1 = 3 edges, but diameter counts edges, so longest path is 3 edges which means 4 nodes.Final Answer:
3 -> Option CQuick Check:
Longest path length = 3 edges [OK]
- Counting nodes instead of edges for diameter
- Ignoring one subtree height
- Confusing height with diameter
func diameterOfBinaryTree(root *TreeNode) int {
maxDiameter := 0
var height func(node *TreeNode) int
height = func(node *TreeNode) int {
if node == nil {
return 0
}
leftHeight := height(node.Left)
rightHeight := height(node.Right)
maxDiameter = leftHeight + rightHeight
if leftHeight > rightHeight {
return leftHeight + 1
}
return rightHeight + 1
}
height(root)
return maxDiameter
}Solution
Step 1: Analyze maxDiameter update
maxDiameter is assigned leftHeight + rightHeight every time, overwriting previous max without comparison.Step 2: Correct maxDiameter update
Should update maxDiameter only if leftHeight + rightHeight is greater than current maxDiameter.Final Answer:
maxDiameter is overwritten without checking max value -> Option DQuick Check:
Use max check before assignment [OK]
- Overwriting maxDiameter without max check
- Forgetting base case for nil node
- Not calling height recursively
Solution
Step 1: Extend height function to track paths
Modify the recursive height function to return both height and the path nodes from current node to leaf.Step 2: Update max diameter and store path
When leftHeight + rightHeight exceeds maxDiameter, update maxDiameter and store concatenated path from left and right subtrees through current node.Step 3: Return stored path after traversal
After full traversal, return the stored path representing the diameter.Final Answer:
Modify height function to return both height and path, update max path when diameter increases -> Option AQuick Check:
Track height and path together for diameter path [OK]
- Trying to find path after diameter without tracking
- Storing all paths wastes memory
- Ignoring path tracking in recursion
Ready to prove it?
Pass the test and this pattern moves unknown
