Vertical Order Traversal of Binary Tree in DSA Go - Time & Space Complexity
We want to understand how the time needed to do vertical order traversal 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 verticalOrder(root *TreeNode) [][]int {
if root == nil {
return [][]int{}
}
type nodeInfo struct {
node *TreeNode
col int
}
queue := []nodeInfo{{root, 0}}
colTable := map[int][]int{}
minCol, maxCol := 0, 0
for len(queue) > 0 {
curr := queue[0]
queue = queue[1:]
colTable[curr.col] = append(colTable[curr.col], curr.node.Val)
if curr.node.Left != nil {
queue = append(queue, nodeInfo{curr.node.Left, curr.col - 1})
if curr.col-1 < minCol {
minCol = curr.col - 1
}
}
if curr.node.Right != nil {
queue = append(queue, nodeInfo{curr.node.Right, curr.col + 1})
if curr.col+1 > maxCol {
maxCol = curr.col + 1
}
}
}
result := [][]int{}
for i := minCol; i <= maxCol; i++ {
result = append(result, colTable[i])
}
return result
}
This code does a breadth-first search to group nodes by their vertical columns.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The main loop processes each node once using a queue.
- How many times: Exactly once per node, so n times for n nodes.
As the number of nodes grows, the loop runs once per node, so the work grows linearly.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 steps |
| 100 | About 100 steps |
| 1000 | About 1000 steps |
Pattern observation: Doubling the nodes roughly doubles the work.
Time Complexity: O(n)
This means the time grows directly in proportion to the number of nodes in the tree.
[X] Wrong: "Because we track columns, the complexity is higher than O(n)."
[OK] Correct: We only visit each node once, and column tracking is done with simple map insertions, so it does not add extra loops over nodes.
Understanding this helps you explain how breadth-first search can be combined with extra information to solve problems efficiently.
"What if we used depth-first search instead of breadth-first search? How would the time complexity change?"
Practice
Solution
Step 1: Understand vertical order traversal concept
Vertical order traversal groups nodes based on their horizontal distance from the root node, also called the vertical column.Step 2: Differentiate from other traversals
Unlike level order which groups by depth, vertical order groups nodes that align vertically when the tree is viewed from top.Final Answer:
Their horizontal distance from the root -> Option DQuick Check:
Vertical order = horizontal distance grouping [OK]
- Confusing vertical order with level order traversal
- Grouping by node values instead of position
- Ignoring horizontal distance concept
Solution
Step 1: Identify grouping requirement
We need to group nodes by their vertical column index, which is an integer key.Step 2: Choose suitable Go data structure
A map with integer keys and slice of integers as values (map[int][]int) allows storing multiple node values per vertical column.Final Answer:
map[int][]int -> Option CQuick Check:
Use map[int][]int for vertical groups [OK]
- Using simple slices without keys
- Using map with string keys unnecessarily
- Choosing 2D slices without keys
1 / \ 2 3 / \ 4 5What is the vertical order traversal output?
Solution
Step 1: Assign horizontal distances
Root 1 is at 0, left child 2 at -1, left-left 4 at -2, right child 3 at +1, right-right 5 at +2.Step 2: Group nodes by horizontal distance
At -2: [4], -1: [2], 0: [1], +1: [3], +2: [5].Final Answer:
[[4], [2], [1], [3, 5]] -> Option BQuick Check:
Group by horizontal distance = [[4], [2], [1], [3, 5]] [OK]
- Mixing node order inside same vertical column
- Incorrect horizontal distance assignment
- Ignoring multiple nodes in same vertical column
func verticalOrder(root *Node) map[int][]int {
result := make(map[int][]int)
var dfs func(node *Node, hd int)
dfs = func(node *Node, hd int) {
if node == nil {
return
}
result[hd] = append(result[hd], node.Val)
dfs(node.Left, hd-1)
dfs(node.Right, hd+1)
}
dfs(root, 0)
return result
}
What is the main issue with this code?Solution
Step 1: Analyze traversal method
The code uses DFS which explores depth first, so nodes deeper may be added before shallower nodes in same vertical column.Step 2: Understand vertical order requirement
Vertical order traversal requires nodes to be output top-to-bottom per vertical column, which BFS preserves but DFS may not.Final Answer:
It uses DFS which may not preserve top-to-bottom order -> Option AQuick Check:
DFS can misorder vertical nodes top-to-bottom [OK]
- Assuming DFS preserves vertical order top-to-bottom
- Ignoring traversal order impact on output
- Thinking map usage causes order issues
Solution
Step 1: Choose traversal preserving top-to-bottom order
BFS visits nodes level by level, ensuring top nodes are processed before lower nodes in same vertical column.Step 2: Store nodes with horizontal distance and sort keys
Use a queue to track nodes and their horizontal distance, store in map[int][]int, then output sorted by keys for left to right order.Final Answer:
Use BFS with a queue storing nodes and their horizontal distance, then sort keys -> Option AQuick Check:
BFS + sorting keys = correct vertical order traversal [OK]
- Using DFS which breaks top-to-bottom order
- Not sorting map keys before printing
- Using stack which reverses order
Ready to prove it?
Pass the test and this pattern moves unknown
