medium Boundary of Binary Tree
Problem Statement
The boundary of the tree is the concatenation of the root, the left boundary, the leaf nodes in left to right order, and the right boundary in the reverse order.
- The left boundary includes all the nodes on the leftmost path from the root, excluding the leftmost leaf.
- The leaf nodes include all nodes that do not have any children, traversed from left to right.
- The right boundary includes all nodes on the rightmost path, excluding the rightmost leaf, but they are recorded in reverse order. Return the values of these boundary nodes in order.
Given the root of a binary tree, return an array containing the values of its boundary.
Examples
Example 1:
- Input: root = [1, null, 5, 2, 4]
- Expected Output: [1, 2, 4, 5]
- Justification: The left boundary is empty,
1is root node, the leaves are 2 and 4, and the right boundary in reverse is 5.
Example 2:
- Input: root = [1, 2, 3, 4, 5, 6, 7, null, null, 9]
- Expected Output: [1,2,4,9,6,7,3]
- Justification: The left boundary is 1 → 2, the leaves are 4, 9, 6, and 7, and the right boundary in reverse is 3.
Example 3:
- Input: root = [1, 2, null, 3, 4]
- Expected Output: [1, 2, 3, 4]
- Justification: The left boundary is 1 → 2, the leaves are 3 and 4, and the right boundary is empty.
Constraints:
- The number of nodes in the tree is in the range [1, 104].
- -1000 <= Node.val <= 1000
Try it yourself
Try solving this question here:
✅ Solution Boundary of Binary Tree
Problem Statement
The boundary of the tree is the concatenation of the root, the left boundary, the leaf nodes in left to right order, and the right boundary in the reverse order.
- The left boundary includes all the nodes on the leftmost path from the root, excluding the leftmost leaf.
- The leaf nodes include all nodes that do not have any children, traversed from left to right.
- The right boundary includes all nodes on the rightmost path, excluding the rightmost leaf, but they are recorded in reverse order. Return the values of these boundary nodes in order.
Given the root of a binary tree, return an array containing the values of its boundary.
Examples
Example 1:
- Input: root = [1, null, 5, 2, 4]
- Expected Output: [1, 2, 4, 5]
- Justification: The left boundary is empty,
1is root node, the leaves are 2 and 4, and the right boundary in reverse is 5.
Example 2:
- Input: root = [1, 2, 3, 4, 5, 6, 7, null, null, 9]
- Expected Output: [1,2,4,9,6,7,3]
- Justification: The left boundary is 1 → 2, the leaves are 4, 9, 6, and 7, and the right boundary in reverse is 3.
Example 3:
- Input: root = [1, 2, null, 3, 4]
- Expected Output: [1, 2, 3, 4]
- Justification: The left boundary is 1 → 2, the leaves are 3 and 4, and the right boundary is empty.
Constraints:
- The number of nodes in the tree is in the range [1, 104].
- -1000 <= Node.val <= 1000
Solution
To solve this problem, we need to traverse the binary tree and collect the nodes that form the boundary. The traversal is divided into three parts: collecting the left boundary, identifying the leaf nodes, and finally collecting the right boundary in reverse order. The challenge lies in ensuring that we don't mistakenly add leaf nodes twice when they are part of the left or right boundary. To manage this, we first focus on gathering the left boundary, then the leaf nodes, and finally the right boundary separately.
This approach works efficiently because it ensures we visit each node exactly once and correctly identify which part of the boundary it belongs to. By dividing the problem into these three tasks, we can ensure a well-organized and accurate traversal of the tree.
Step-by-Step Algorithm
-
Check if the root is null:
- If the root is null, return an empty result list because there is no boundary to collect.
-
Add the root to the result list:
- If the root is not a leaf (it has at least one child), add the root’s value to the result list.
-
Collect the left boundary using BFS:
- Initialize a queue and add the left child of the root to it.
- While the queue is not empty, do the following:
- Poll the front node from the queue.
- If the node is not a leaf (it has at least one child), add its value to the result list.
- If the node has a left child, add it to the queue. Otherwise, if it has a right child, add that to the queue. This ensures that we only collect the nodes that are part of the left boundary.
-
Collect the leaf nodes:
- Recursively traverse the tree from the root:
- For each node, check if it is a leaf (it has no children). If it is, add its value to the result list.
- If the node is not a leaf, recursively traverse its left and right children, continuing to search for leaves.
- Recursively traverse the tree from the root:
-
Collect the right boundary using BFS:
- Initialize a stack and add the right child of the root to it.
- While the stack is not empty, do the following:
- Poll the front node from the queue.
- If the node is not a leaf (it has at least one child), push its value onto the stack.
- If the node has a right child, add it to the queue. Otherwise, if it has a left child, add that to the queue. This ensures that we only collect the nodes that are part of the right boundary.
- Once the BFS is complete, pop the elements from the stack and add them to the result list to ensure the right boundary is added in reverse order.
-
Return the final result list:
- After collecting the root, left boundary, leaf nodes, and right boundary, return the result list containing the boundary nodes.
Algorithm Walkthrough
Input Tree Structure:
The binary tree for the given input looks like this:
1
/ \
2 3
/ \ / \
4 5 6 7
/
9
Steps:
-
Step 1 - Check if the tree is empty:
- The root is not
null, so we proceed with the boundary collection process.
- The root is not
-
Step 2 - Add the root node to the result list:
- The root node is
1, and since it's not a leaf (it has both left and right children), we add1to the result list. - Current
result = [1].
- The root node is
-
Step 3 - Collect the left boundary using BFS:
-
We start collecting the left boundary nodes by performing a BFS traversal starting from the left child of the root (
root.left = 2). -
Iteration 1:
- The node we are processing is
2. It's not a leaf, so we add it to the result list. - Add its left child (
4) to the queue. result = [1, 2].
- The node we are processing is
-
Iteration 2:
- The node we are processing is
4. Since4is a leaf (no left or right children), we stop collecting further left boundary nodes. - Note: Although node
4is part of the left boundary, it will be handled later during leaf collection.
- The node we are processing is
-
Left boundary collection is complete.
-
-
Step 4 - Collect the leaf nodes:
-
Now, we need to collect all the leaf nodes of the tree. We perform a DFS traversal and collect leaf nodes from both the left and right subtrees of the root.
-
Traversing the left subtree:
-
Start from the left child of the root (
root.left = 2). -
Node 2:
-
Node
2is not a leaf, so we recurse to its children. -
Node 4:
- Node
4is a leaf (no left or right children). Add4to the result list. result = [1, 2, 4].
- Node
-
Node 5:
-
Node
5is not a leaf, so we recurse to its left child. -
Node 9:
- Node
9is a leaf (no left or right children). Add9to the result list. result = [1, 2, 4, 9].
- Node
-
-
-
-
Traversing the right subtree:
-
Now, we traverse the right subtree of the root (
root.right = 3). -
Node 3:
-
Node
3is not a leaf, so we recurse to its children. -
Node 6:
- Node
6is a leaf (no left or right children). Add6to the result list. result = [1, 2, 4, 9, 6].
- Node
-
Node 7:
- Node
7is a leaf (no left or right children). Add7to the result list. result = [1, 2, 4, 9, 6, 7].
- Node
-
-
-
Leaf collection is complete.
-
-
Step 5 - Collect the right boundary using BFS:
-
Finally, we collect the right boundary nodes. We perform a BFS traversal starting from the right child of the root (
root.right = 3), but we collect the nodes in reverse order. -
Iteration 1:
- The node we are processing is
3. It's not a leaf, so we push3onto the stack. - Add its right child (
7) to the queue. Since7is a leaf, it is not processed further as part of the right boundary. - Stack after this iteration:
stack = [3].
- The node we are processing is
-
Right boundary collection is complete. We now pop the elements from the stack (to reverse the order) and add them to the result list.
- Pop
3from the stack and add it to the result. result = [1, 2, 4, 9, 6, 7, 3].
- Pop
-
-
Step 6 - Return the final result:
- After collecting the root, left boundary, leaf nodes, and right boundary, the final result is:
- Final Output:
[1, 2, 4, 9, 6, 7, 3].
Final Explanation:
- Left boundary: Nodes
1 → 2are part of the left boundary. - Leaf nodes: The leaf nodes are
4, 9, 6, and 7. - Right boundary: The right boundary is node
3, and it is added to the result in reverse order.
Thus, the boundary of the tree for the given input is [1, 2, 4, 9, 6, 7, 3].
Code
import java.util.*;
// class TreeNode {
// int val;
// TreeNode left;
// TreeNode right;
// TreeNode(int val) {
// this.val = val;
// this.left = null;
// this.right = null;
// }
// }
public class Solution {
// Method to check if a node is a leaf.
private boolean isLeaf(TreeNode node) {
return node.left == null && node.right == null;
}
// Method to add the left boundary using BFS.
private void addLeftBoundaryBFS(TreeNode root, List<Integer> result) {
Queue<TreeNode> queue = new LinkedList<>();
if (root != null) queue.add(root);
while (!queue.isEmpty()) {
TreeNode node = queue.poll();
// Only add nodes that are part of the left boundary and are not leaves.
if (node.left != null || node.right != null) {
result.add(node.val);
}
// Continue BFS on the left side.
if (node.left != null) {
queue.add(node.left);
} else if (node.right != null) {
queue.add(node.right);
}
}
}
// Method to add leaves using BFS.
private void addLeaves(TreeNode node, List<Integer> result) {
if (node == null) return;
// If it's a leaf, add it to the result.
if (isLeaf(node)) {
result.add(node.val);
} else {
// Recurse for left and right subtrees.
addLeaves(node.left, result);
addLeaves(node.right, result);
}
}
// Method to add the right boundary using BFS.
private void addRightBoundaryBFS(TreeNode root, List<Integer> result) {
Stack<Integer> stack = new Stack<>(); // We will store right boundary nodes in reverse order.
Queue<TreeNode> queue = new LinkedList<>();
if (root != null) queue.add(root);
while (!queue.isEmpty()) {
TreeNode node = queue.poll();
// Only add nodes that are part of the right boundary and are not leaves.
if (node.left != null || node.right != null) {
stack.push(node.val);
}
// Continue BFS on the right side.
if (node.right != null) {
queue.add(node.right);
} else if (node.left != null) {
queue.add(node.left);
}
}
// Now add nodes from the stack to the result list (reversed order).
while (!stack.isEmpty()) {
result.add(stack.pop());
}
}
public List<Integer> boundaryOfBinaryTree(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null) return result;
// Step 1: Add the root (if it's not a leaf).
if (!isLeaf(root)) {
result.add(root.val);
}
// Step 2: Add the left boundary.
addLeftBoundaryBFS(root.left, result);
// Step 3: Add the leaf nodes.
addLeaves(root, result);
// Step 4: Add the right boundary.
addRightBoundaryBFS(root.right, result);
return result;
}
public static void main(String[] args) {
Solution sol = new Solution();
// Construct the binary tree for the given example:
// Input: root = [1, 2, 3, 4, 5, 6, 7, null, null, 9]
TreeNode root = new TreeNode(1);
root.left = new TreeNode(2);
root.right = new TreeNode(3);
root.left.left = new TreeNode(4);
root.left.right = new TreeNode(5);
root.right.left = new TreeNode(6);
root.right.right = new TreeNode(7);
root.left.right.left = new TreeNode(9); // Node 9
// Call the method and print the boundary.
List<Integer> boundary = sol.boundaryOfBinaryTree(root);
System.out.println(boundary); // Expected Output: [1, 2, 4, 9, 6, 7, 3]
}
}
Complexity Analysis
Time Complexity
- Left Boundary Traversal: The
addLeftBoundaryBFS()method traverses the left side of the tree, visiting each node once. The time complexity of this traversal is, where his the height of the tree. - Leaf Collection: The
addLeaves()function performs a full tree traversal to collect all the leaves. This takes, where nis the number of nodes in the tree. - Right Boundary Traversal: The
addRightBoundaryBFS()function traverses the right side of the tree and uses a stack to reverse the right boundary nodes. The time complexity for this traversal isas it visits the right boundary nodes and reverses them.
The overall time complexity is the sum of the three traversals, which is
Space Complexity:
- Queue/Stack Usage: Both BFS traversals use a queue and a stack, with at most
space being used at any point, where his the height of the tree. - Recursion for Leaves: The
addLeaves()function is a recursive function, so the recursion stack will have a space complexity of. - Result List: The result list will store all the boundary nodes, which in the worst case is
.
Thus, the overall space complexity is n is the number of nodes in the tree.
🤖 Don't fully get this? Learn it with Claude
Stuck on Boundary of Binary Tree? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.
Progressively stronger hints — you still solve it.
I'm working on the problem **Boundary of Binary Tree** (DSA). Give me a HINT LADDER: start with the tiniest nudge, then wait. Only reveal the next, stronger hint when I ask. Do NOT show the full solution unless I type 'show solution'. Keep me doing the thinking. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
See the technique, not just code.
Explain the optimal approach to **Boundary of Binary Tree** with a VISUAL walkthrough: trace it on a small concrete example using ASCII art / a step-by-step diagram, narrate what changes each step, then give time & space complexity with a one-line derivation. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Catch bugs, edge cases, sub-optimality.
I'll paste my solution to **Boundary of Binary Tree**. Review it for correctness, missed edge cases, and time/space complexity, then coach me toward the optimal — don't just rewrite it. Ask me to paste my code now. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Lock in recognition with look-alikes.
Give me 2 problems that use the SAME underlying pattern as **Boundary of Binary Tree**. For each, let me attempt first, then review my answer and name the trigger signal that reveals the pattern. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.