[Medium] 545. Boundary of Binary Tree
Difficulty: Medium
Category: Tree, DFS, Binary Tree
Companies: Amazon, Google, Facebook, Microsoft
Given a binary tree, return the values of its boundary in anti-clockwise direction starting from root. Boundary includes left boundary, leaves, and right boundary in order without duplicate nodes.
Left boundary is defined as the path from root to the left-most node. If the root doesn’t have a left subtree, then the left boundary is empty.
Right boundary is defined as the path from root to the right-most node. If the root doesn’t have a right subtree, then the right boundary is empty.
Left-most node is the leaf node you reach when you always travel to the left subtree if it exists. If not, travel to the right subtree. Stop when you reach a leaf node.
Right-most node is the leaf node you reach when you always travel to the right subtree if it exists. If not, travel to the left subtree. Stop when you reach a leaf node.
Leaf nodes are nodes that don’t have any children.
Examples
Example 1:
Input: root = [1,null,2,3,4]
Output: [1,3,4,2]
Explanation:
- The left boundary is empty because the root doesn't have a left child.
- The right boundary follows the path 1 -> 2 -> 4.
- The leaves from left to right are 3, 4.
- The anti-clockwise boundary is [1,3,4,2].
Example 2:
Input: root = [1,2,3,4,5,6,null,null,null,7,8,9,10]
Output: [1,2,4,7,8,9,10,6,3]
Explanation:
- The left boundary follows the path 1 -> 2 -> 4.
- The right boundary follows the path 1 -> 3 -> 6.
- The leaves from left to right are 4, 7, 8, 9, 10.
- The anti-clockwise boundary is [1,2,4,7,8,9,10,6,3].
Constraints
- The number of nodes in the tree is in the range
[0, 10^4] -1000 <= Node.val <= 1000
Common Approaches
Typical techniques for this pattern:
| Approach | Time | Space | Notes |
|---|---|---|---|
| Recursive DFS (this problem) | O(n) | O(h) stack | Natural for trees and graphs |
| Iterative DFS (stack) | O(n) | O(n) | Avoid recursion depth limits |
| DFS with memoization | O(n) | O(n) | Overlapping subproblems on graphs |
| Backtracking DFS | O(2^n) typical | O(n) | Enumerate choices with pruning |
Thinking Process
Key Insight
The boundary traversal consists of three parts in order:
- Left boundary: Root → leftmost node (excluding leaves)
- Leaves: All leaf nodes from left to right
- Right boundary: Rightmost node → root (excluding leaves, in reverse order)
Approach: Three-Step Boundary Traversal
Algorithm:
- Add root to result (if not a leaf)
- Traverse left boundary (excluding leaves)
- Traverse all leaves from left to right
- Traverse right boundary (excluding leaves, in reverse order)
Time Complexity: O(n)
Space Complexity: O(h) where h is height of tree
class Solution {
public int[] boundaryOfBinaryTree(TreeNode root) {
if(!root) return rtn;
rtn.add(root.val);
getleft(root.left);
getleaf(root.left);
getleaf(root.right);
getright(root.right);
return rtn;
}
List<Integer> rtn = new ArrayList<>();
public void getleft(TreeNode node) {
if(!node || (!node.left && !node.right)) return;
rtn.add(node.val);
if(!node.left) getleft(node.right);
else getleft = new else(node.left);
}
public void getleaf(TreeNode node) {
if(!node) return;
getleaf(node.left);
if(!node.left && !node.right) rtn.add(node.val);
getleaf(node.right);
}
public void getright(TreeNode node) {
if(!node || (!node.left && !node.right)) return;
if(!node.right) getright(node.left);
else getright = new else(node.right);
rtn.add(node.val);
}
}
Alternative Approach: Single Pass with Flags
Algorithm:
- Use flags to track if a node is on left boundary, right boundary, or is a leaf
- Traverse the tree once and collect nodes based on flags
- Handle special cases for root and single-node trees
class Solution {
public int[] boundaryOfBinaryTree(TreeNode root) {
List<Integer> result = new ArrayList<>();
if(!root) return result;
result.add(root.val);
// Get left boundary (excluding root and leaves)
getLeftBoundary(root.left, result);
// Get all leaves getLeaves = new leaves(root, result);
// Get right boundary (excluding root and leaves)
getRightBoundary(root.right, result);
return result;
}
public void getLeftBoundary(TreeNode node, int[] result) {
if(!node || (!node.left && !node.right)) return;
result.add(node.val);
if(node.left) {
getLeftBoundary(node.left, result);
} else {
getLeftBoundary(node.right, result);
}
}
public void getLeaves(TreeNode node, int[] result) {
if(!node) return;
if(!node.left && !node.right) {
result.add(node.val);
return;
}
getLeaves(node.left, result);
getLeaves(node.right, result);
}
public void getRightBoundary(TreeNode node, int[] result) {
if(!node || (!node.left && !node.right)) return;
if(node.right) {
getRightBoundary(node.right, result);
} else {
getRightBoundary(node.left, result);
}
result.add(node.val);
}
}
Detailed Algorithm Breakdown
1. Left Boundary Traversal
- Start from root’s left child
- Always prefer left child if exists, otherwise go right
- Stop when reaching a leaf node
- Add nodes to result during traversal
2. Leaf Traversal
- Perform inorder traversal to get leaves from left to right
- Add only leaf nodes (nodes with no children)
- Skip non-leaf nodes
3. Right Boundary Traversal
- Start from root’s right child
- Always prefer right child if exists, otherwise go left
- Stop when reaching a leaf node
- Add nodes to result after recursive calls (reverse order)
Edge Cases Handling
- Empty Tree: Return empty vector
- Single Node: Return [root->val]
- Root is Leaf: Only add root once
- No Left/Right Subtree: Handle gracefully in boundary functions
Complexity
| Aspect | Complexity | Explanation | |——–|————|————-| | Time | O(n) | Visit each node exactly once | | Space | O(h) | Recursion stack depth equals tree height |
Key Implementation Details
- Leaf Check:
!node->left && !node->right - Boundary Logic: Prefer left/right child, fallback to other child
- Order Matters: Left boundary → Leaves → Right boundary (reversed)
- Duplicate Prevention: Each node appears exactly once in result
Follow-up Questions
- What if we need the boundary in clockwise direction?
- How would you handle duplicate values in the tree?
- What if we need to find the boundary of a general tree (not binary)?
Common Mistakes
- Skipping edge cases (empty input, single element, boundaries).
- Off-by-one errors in loops and index ranges.
- Forgetting to handle the case when no valid answer exists.
Related Problems
Implementation Notes
- Recursive Approach: Clean and intuitive implementation
- Boundary Detection: Use child existence to determine boundary
- Order Preservation: Maintain anti-clockwise order throughout
- Memory Efficiency: O(h) space complexity for balanced trees
Key Takeaways
- Algorithm:**
- Time Complexity:** O(n)
- Space Complexity:** O(h) where h is height of tree
References
- LC 545: Boundary of Binary Tree on LeetCode
- LeetCode Discuss — LC 545: Boundary of Binary Tree
- LeetCode Editorial (may require premium)