Bottom View of Binary Tree in DSA Rust - Time & Space Complexity
We want to understand how the time needed to find the bottom view of a binary tree changes as the tree grows.
How does the number of nodes affect the work done?
Analyze the time complexity of the following code snippet.
use std::collections::{HashMap, VecDeque};
fn bottom_view(root: &Option>) -> Vec {
let mut map = HashMap::new();
let mut queue = VecDeque::new();
queue.push_back((root.as_ref(), 0));
while let Some((node_opt, hd)) = queue.pop_front() {
if let Some(node) = node_opt {
map.insert(hd, node.val);
queue.push_back((node.left.as_ref(), hd - 1));
queue.push_back((node.right.as_ref(), hd + 1));
}
}
let mut keys: Vec<_> = map.keys().cloned().collect();
keys.sort();
keys.iter().map(|k| map[k]).collect()
}
This code finds the bottom view of a binary tree by level order traversal, tracking horizontal distances.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The while loop that visits each node once.
- How many times: Exactly once per node in the tree (n times).
As the number of nodes grows, the code visits each node once, doing a constant amount of work per node.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 visits and updates |
| 100 | About 100 visits and updates |
| 1000 | About 1000 visits and updates |
Pattern observation: The work grows linearly with the number of nodes.
Time Complexity: O(n log n)
This means the time grows a bit more than linearly because of sorting the horizontal distances at the end.
[X] Wrong: "The time complexity is just O(n) because we visit each node once."
[OK] Correct: We also sort the keys of the horizontal distances, which can take O(k log k) time, where k is the number of unique horizontal distances, up to n.
Understanding how traversal and sorting combine helps you explain your solution clearly and shows you can analyze combined steps in algorithms.
What if we used a balanced tree map instead of a hash map to store horizontal distances? How would the time complexity change?
Practice
bottom view of a binary tree represent?Solution
Step 1: Understand the bottom view concept
The bottom view shows nodes visible when looking at the tree from below, meaning the lowest nodes at each horizontal distance.Step 2: Compare with other views
Top view shows nodes from above, left and right views show nodes from sides, so bottom view is unique for bottom perspective.Final Answer:
Nodes visible when the tree is viewed from the bottom -> Option CQuick Check:
Bottom view = nodes visible from below [OK]
- Confusing bottom view with top view
- Thinking bottom view is left or right side view
- Assuming all nodes are visible in bottom view
Solution
Step 1: Identify the need for horizontal distance mapping
We need to map horizontal distances (integers) to nodes, so a key-value structure is required.Step 2: Choose appropriate Rust data structure
HashMap allows storing nodes with horizontal distance keys efficiently.Final Answer:
HashMap<i32, Node> -> Option BQuick Check:
Use HashMap for horizontal distance mapping [OK]
- Using Vec which doesn't map keys to values
- Using LinkedList which is sequential, not key-based
- Using BinaryHeap which is for priority, not mapping
struct Node {
val: i32,
left: Option,
right: Option,
}
// Tree:
// 1
// / \
// 2 3
// \ \
// 4 5
// Bottom view expected: 2 -> 4 -> 3 -> 5
fn main() {
// Assume bottom_view function returns Vec<i32> of bottom view nodes
let bottom = vec![2, 4, 3, 5];
for val in bottom {
print!("{} -> ", val);
}
print!("null\n");
}Solution
Step 1: Understand the tree structure and bottom view
The tree has nodes 2,4,3,5 visible from bottom at horizontal distances -1,0,1,2 respectively.Step 2: Trace the printed output from the vector
The vector contains [2,4,3,5], printed with arrows and ending with null.Final Answer:
2 -> 4 -> 3 -> 5 -> null -> Option DQuick Check:
Bottom view print matches vector [OK]
- Confusing node order in bottom view
- Printing all nodes instead of bottom view nodes
- Missing the final 'null' in output
fn bottom_view(root: Option) -> Vec<i32> {
let mut map = std::collections::HashMap::new();
let mut queue = std::collections::VecDeque::new();
queue.push_back((root.unwrap(), 0));
while let Some((node, hd)) = queue.pop_front() {
map.insert(hd, node.val);
if let Some(left) = node.left {
queue.push_back((left, hd - 1));
}
if let Some(right) = node.right {
queue.push_back((right, hd + 1));
}
}
let mut keys: Vec<_> = map.keys().cloned().collect();
keys.sort();
keys.iter().map(|k| map[k]).collect()
}Solution
Step 1: Check root unwrap usage
Calling unwrap() on root without checking if root is None can cause panic if tree is empty.Step 2: Verify other logic correctness
Horizontal distances and map updates are correct; keys are sorted before collecting nodes.Final Answer:
Using unwrap() on root without checking if it's None -> Option AQuick Check:
unwrap() on None causes panic [OK]
- Ignoring possibility of empty tree causing panic
- Assuming map updates only once per horizontal distance
- Forgetting to sort keys before output
Solution
Step 1: Understand the need to track depth
Bottom view requires the lowest node at each horizontal distance, so depth must be tracked.Step 2: Modify map to store node value and depth
Store tuple (value, depth) and update map only if new node's depth is greater or equal to existing depth.Step 3: Ignore other options
Overwriting blindly loses depth info; stack changes traversal order; sorting by value doesn't solve depth issue.Final Answer:
Store (node value, depth) in the map and update only if new depth >= stored depth -> Option AQuick Check:
Track depth to keep bottom-most node [OK]
- Ignoring node depth leading to wrong bottom view
- Overwriting map entries without depth check
- Changing traversal method without addressing depth
Ready to prove it?
Pass the test and this pattern moves unknown
