Maximum Width of Binary Tree in DSA Go - Time & Space Complexity
We want to understand how the time needed to find the maximum width of a binary tree grows as the tree gets bigger.
Specifically, how does the number of nodes affect the work done?
Analyze the time complexity of the following code snippet.
func widthOfBinaryTree(root *TreeNode) int {
if root == nil {
return 0
}
maxWidth := 0
queue := []struct{
node *TreeNode
index int
}{{root, 0}}
for len(queue) > 0 {
size := len(queue)
start := queue[0].index
end := queue[size-1].index
if end - start + 1 > maxWidth {
maxWidth = end - start + 1
}
for i := 0; i < size; i++ {
curr := queue[0]
queue = queue[1:]
if curr.node.Left != nil {
queue = append(queue, struct{node *TreeNode; index int}{curr.node.Left, 2*curr.index + 1})
}
if curr.node.Right != nil {
queue = append(queue, struct{node *TreeNode; index int}{curr.node.Right, 2*curr.index + 2})
}
}
}
return maxWidth
}
This code finds the maximum width of a binary tree by level-order traversal, tracking node positions.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The outer loop runs once per level of the tree, and the inner loop processes every node at that level.
- How many times: Each node is visited exactly once during the traversal.
As the number of nodes (n) increases, the code visits each node once, so the total work grows directly with n.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 visits and checks |
| 100 | About 100 visits and checks |
| 1000 | About 1000 visits and checks |
Pattern observation: The work grows linearly with the number of nodes.
Time Complexity: O(n)
This means the time to find the maximum width grows in direct proportion to the number of nodes in the tree.
[X] Wrong: "The time complexity depends on the maximum width of the tree, not the total nodes."
[OK] Correct: Even if the width is large, the algorithm must visit every node once, so total nodes determine the time, not just the width.
Understanding how tree traversal time grows helps you explain your approach clearly and shows you know how to analyze algorithms well.
"What if we used recursion instead of a queue for level-order traversal? How would the time complexity change?"
Practice
Solution
Step 1: Understand the definition of width in a binary tree
The width is the count of nodes at a particular level in the tree.Step 2: Identify maximum width
The maximum width is the largest such count among all levels.Final Answer:
The largest number of nodes present at any single level of the tree -> Option DQuick Check:
Maximum width = max nodes at any level [OK]
- Confusing width with height of the tree
- Thinking width is sum of node values
- Counting total nodes instead of per level
Solution
Step 1: Identify traversal method for level order
Level order traversal requires processing nodes level by level, which is done using a queue.Step 2: Choose data structure
A queue allows nodes to be added at the end and removed from the front, perfect for breadth-first traversal.Final Answer:
Queue -> Option AQuick Check:
Level order traversal uses queue [OK]
- Using stack which is LIFO, not suitable for level order
- Using map which doesn't preserve order
- Using slice without queue operations
type TreeNode struct {
Val int
Left, Right *TreeNode
}
func maxWidth(root *TreeNode) int {
if root == nil {
return 0
}
queue := []*TreeNode{root}
maxWidth := 0
for len(queue) > 0 {
levelSize := len(queue)
if levelSize > maxWidth {
maxWidth = levelSize
}
for i := 0; i < levelSize; i++ {
node := queue[0]
queue = queue[1:]
if node.Left != nil {
queue = append(queue, node.Left)
}
if node.Right != nil {
queue = append(queue, node.Right)
}
}
}
return maxWidth
}
root := &TreeNode{Val: 1}
root.Left = &TreeNode{Val: 2}
root.Right = &TreeNode{Val: 3}
root.Left.Left = &TreeNode{Val: 4}
root.Right.Right = &TreeNode{Val: 5}
fmt.Println(maxWidth(root))Solution
Step 1: Analyze tree structure and levels
Level 1: Node 1 (1 node), Level 2: Nodes 2 and 3 (2 nodes), Level 3: Nodes 4 and 5 (2 nodes)Step 2: Calculate maximum width
Maximum width is the largest number of nodes at any level, which is 2.Step 3: Re-examine the tree structure carefully
Actually, at Level 3, nodes are 4 and 5 (2 nodes), but at Level 2, nodes are 2 and 3 (2 nodes), so max width is 2. However, the code counts the queue size before processing children, so at Level 1 queue size is 1, Level 2 queue size is 2, Level 3 queue size is 2. The maximum width is 2.Step 4: Check if any level has 3 nodes
No level has 3 nodes, so 3 (3) is incorrect.Final Answer:
2 -> Option BQuick Check:
Max nodes at any level = 2 [OK]
- Counting total nodes instead of per level
- Miscounting nodes at last level
- Assuming root level has more nodes
func maxWidth(root *TreeNode) int {
if root == nil {
return 0
}
queue := []*TreeNode{root}
maxWidth := 0
for len(queue) > 0 {
levelSize := len(queue)
if levelSize > maxWidth {
maxWidth = levelSize
}
for i := 0; i <= levelSize; i++ {
node := queue[0]
queue = queue[1:]
if node.Left != nil {
queue = append(queue, node.Left)
}
if node.Right != nil {
queue = append(queue, node.Right)
}
}
}
return maxWidth
}Solution
Step 1: Check loop boundaries for processing nodes
The inner loop runs from i = 0 to i <= levelSize, which means it runs levelSize + 1 times, causing out-of-range error.Step 2: Correct loop condition
The loop should run exactly levelSize times, so condition must be i < levelSize.Final Answer:
The inner loop condition should be i < levelSize, not i <= levelSize -> Option AQuick Check:
Loop runs one extra time causing error [OK]
- Using <= instead of < in loop condition
- Initializing queue incorrectly
- Updating maxWidth at wrong time
Solution
Step 1: Understand the problem of null gaps
Normal width counts nodes only, but to include gaps, we track positions of nodes as if tree was complete.Step 2: Use index tracking with queue
Store each node with an index representing its position. For each level, width = last index - first index + 1.Step 3: Implement with queue of (node, index) pairs
This approach allows measuring width including null gaps between nodes.Final Answer:
Use a queue storing pairs of (node, index) where index represents position, and calculate width as max index difference per level -> Option CQuick Check:
Index tracking captures null gaps in width [OK]
- Ignoring null gaps by counting only nodes
- Using recursion without position tracking
- Calculating width as total nodes divided by height
Ready to prove it?
Pass the test and this pattern moves unknown
