Talentd
FleetCode
Make and follow sheets.Sign in

Boundary of Binary Tree solution and explanation

MediumBinary TreeDepth-First SearchTree7 min read48.0% acceptanceUpdated 23 Mar 2026Premium elsewhere, free here
LeetCode 545. Boundary of Binary TreeHappy Coding · 21:52 · 6K viewsWatch on YouTube
9 more videos on this problem
  1. LeetCode 545. Boundary of Binary TreeHappy Coding · 21:52 · 6K views
  2. 545. Boundary of Binary Tree (Leetcode Medium)Programming Live with Larry · 11:28 · 2K views
  3. Amazon Coding Interview Question | Leetcode 545 | Boundary of Binary TreeWorkWithGoogler · 8:37 · 1K views
  4. LeetCode 545 Boundary of Binary Treechen xiang · 14:27 · 1K views
  5. Leetcode 545 Boundary of Binary Tree - Google, Amazon Interview Question Java SolutionAlgorithmicIQ · 17:30 · 692 views
  6. leetcode 545. Boundary of Binary Tree - different flavors of traversalCode-Yao · 17:13 · 218 views
  7. Leetcode 545. Boundary of Binary Tree (tree traversal)LetsCode · 13:05 · 156 views
  8. Leetcode 545 Solution Tutorial - Boundary Of Binary Tree Javascript Leetcode SolnTKD's Health Tips · 7:38 · 140 views
  9. LeetCode 545. Boundary of Binary Treekatryo · 52:11 · 138 views
  10. Leetcode 545 Boundary of Binary TreeDev_God · 11:26 · 95 views

The problem

The boundary of a binary tree is the concatenation of the root, the left boundary, the leaves ordered from left-to-right, and the reverse order of the right boundary.

The left boundary is the set of nodes defined by the following:

  • The root node's left child is in the left boundary. If the root does not have a left child, then the left boundary is empty.
  • If a node is in the left boundary and has a left child, then the left child is in the left boundary.
  • If a node is in the left boundary, has no left child, but has a right child, then the right child is in the left boundary.
  • The leftmost leaf is not in the left boundary.

The right boundary is similar to the left boundary, except it is the right side of the root's right subtree. Again, the leaf is not part of the right boundary, and the right boundary is empty if the root does not have a right child.

The leaves are nodes that do not have any children. For this problem, the root is not a leaf.

Given the root of a binary tree, return the values of its boundary.

Example 1:

Input: root = [1,null,2,3,4]
Output: [1,3,4,2]
Explanation:
- The left boundary is empty because the root does not have a left child.
- The right boundary follows the path starting from the root's right child 2 -> 4.
  4 is a leaf, so the right boundary is [2].
- The leaves from left to right are [3,4].
Concatenating everything results in [1] + [] + [3,4] + [2] = [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 starting from the root's left child 2 -> 4.
  4 is a leaf, so the left boundary is [2].
- The right boundary follows the path starting from the root's right child 3 -> 6 -> 10.
  10 is a leaf, so the right boundary is [3,6], and in reverse order is [6,3].
- The leaves from left to right are [4,7,8,9,10].
Concatenating everything results in [1] + [2] + [4,7,8,9,10] + [6,3] = [1,2,4,7,8,9,10,6,3].

Constraints:

  • The number of nodes in the tree is in the range [1, 104].
  • -1000 <= Node.val <= 1000

Approach overview

Problem Overview: Given a binary tree, return its boundary traversal in anti-clockwise order starting from the root. The boundary includes the left boundary, all leaf nodes, and the right boundary (added in reverse order) without duplicates.

Approach 1: DFS with Boundary Classification (O(n) time, O(h) space)

This approach performs a depth-first traversal while classifying each node as part of the left boundary, right boundary, or a leaf. The root is always included first. During DFS, you propagate two flags: isLeftBoundary and isRightBoundary. If a node is on the left boundary, append it before exploring children. If it is a leaf (no children), add it directly. If it is on the right boundary, append it after exploring children so the final order becomes reversed automatically. This technique ensures each node is processed exactly once, giving O(n) time complexity and O(h) recursion stack space where h is tree height. The traversal naturally fits problems involving depth-first search on a binary tree.

Approach 2: Separate Traversals for Left Boundary, Leaves, and Right Boundary (O(n) time, O(h) space)

This method splits the work into three clear steps. First, iterate down the left side of the tree and collect non-leaf nodes to build the left boundary. Second, run a DFS across the tree to collect all leaf nodes in left-to-right order. Third, traverse the right side of the tree and push non-leaf nodes to a temporary list, then reverse it before appending to the result. Each step touches nodes at most once, so the total runtime remains O(n). Space complexity is O(h) due to recursion during the leaf DFS and the temporary storage for the right boundary. The logic is straightforward and commonly used in tree traversal problems.

Recommended for interviews: The DFS boundary-classification approach is usually preferred. It processes the tree in a single traversal and demonstrates strong control over DFS state and traversal order. The three-step traversal approach is easier to reason about and still optimal, which makes it a good starting point during interviews before refining into the single-pass DFS solution.

Solution

First, if the tree has only one node, we directly return a list with the value of that node.

Otherwise, we can use depth-first search (DFS) to find the left boundary, leaf nodes, and right boundary of the binary tree.

Specifically, we can use a recursive function dfs to find these three parts. In the dfs function, we need to pass in a list nums, a node root, and an integer i, where nums is used to store the current part's node values, and root and i represent the current node and the type of the current part (left boundary, leaf nodes, or right boundary), respectively.

The function implementation is as follows:

  • If root is null, then directly return.
  • If i = 0, we need to find the left boundary. If root is not a leaf node, we add the value of root to nums. If root has a left child, we recursively call the dfs function, passing in nums, the left child of root, and i. Otherwise, we recursively call the dfs function, passing in nums, the right child of root, and i.
  • If i = 1, we need to find the leaf nodes. If root is a leaf node, we add the value of root to nums. Otherwise, we recursively call the dfs function, passing in nums, the left child of root and i, as well as nums, the right child of root and i.
  • If i = 2, we need to find the right boundary. If root is not a leaf node, we add the value of root to nums. If root has a right child, we recursively call the dfs function, passing in nums, the right child of root, and i. Otherwise, we recursively call the dfs function, passing in nums, the left child of root, and i.

We call the dfs function separately to find the left boundary, leaf nodes, and right boundary, and then concatenate these three parts to get the answer.

The time complexity is O(n) and the space complexity is O(n), where n is the number of nodes in the binary tree.

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def boundaryOfBinaryTree(self, root: Optional[TreeNode]) -> List[int]:
        def dfs(nums: List[int], root: Optional[TreeNode], i: int):
            if root is None:
                return
            if i == 0:
                if root.left != root.right:
                    nums.append(root.val)
                    if root.left:
                        dfs(nums, root.left, i)
                    else:
                        dfs(nums, root.right, i)
            elif i == 1:
                if root.left == root.right:
                    nums.append(root.val)
                else:
                    dfs(nums, root.left, i)
                    dfs(nums, root.right, i)
            else:
                if root.left != root.right:
                    nums.append(root.val)
                    if root.right:
                        dfs(nums, root.right, i)
                    else:
                        dfs(nums, root.left, i)

        ans = [root.val]
        if root.left == root.right:
            return ans
        left, leaves, right = [], [], []
        dfs(left, root.left, 0)
        dfs(leaves, root, 1)
        dfs(right, root.right, 2)
        ans += left + leaves + right[::-1]
        return ans
class Solution {
    public List<Integer> boundaryOfBinaryTree(TreeNode root) {
        List<Integer> ans = new ArrayList<>();
        ans.add(root.val);
        if (root.left == root.right) {
            return ans;
        }
        List<Integer> left = new ArrayList<>();
        List<Integer> leaves = new ArrayList<>();
        List<Integer> right = new ArrayList<>();
        dfs(left, root.left, 0);
        dfs(leaves, root, 1);
        dfs(right, root.right, 2);

        ans.addAll(left);
        ans.addAll(leaves);
        Collections.reverse(right);
        ans.addAll(right);
        return ans;
    }

    private void dfs(List<Integer> nums, TreeNode root, int i) {
        if (root == null) {
            return;
        }
        if (i == 0) {
            if (root.left != root.right) {
                nums.add(root.val);
                if (root.left != null) {
                    dfs(nums, root.left, i);
                } else {
                    dfs(nums, root.right, i);
                }
            }
        } else if (i == 1) {
            if (root.left == root.right) {
                nums.add(root.val);
            } else {
                dfs(nums, root.left, i);
                dfs(nums, root.right, i);
            }
        } else {
            if (root.left != root.right) {
                nums.add(root.val);
                if (root.right != null) {
                    dfs(nums, root.right, i);
                } else {
                    dfs(nums, root.left, i);
                }
            }
        }
    }
}
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<int> boundaryOfBinaryTree(TreeNode* root) {
        auto dfs = [&](this auto&& dfs, vector<int>& nums, TreeNode* root, int i) -> void {
            if (!root) {
                return;
            }
            if (i == 0) {
                if (root->left != root->right) {
                    nums.push_back(root->val);
                    if (root->left) {
                        dfs(nums, root->left, i);
                    } else {
                        dfs(nums, root->right, i);
                    }
                }
            } else if (i == 1) {
                if (root->left == root->right) {
                    nums.push_back(root->val);
                } else {
                    dfs(nums, root->left, i);
                    dfs(nums, root->right, i);
                }
            } else {
                if (root->left != root->right) {
                    nums.push_back(root->val);
                    if (root->right) {
                        dfs(nums, root->right, i);
                    } else {
                        dfs(nums, root->left, i);
                    }
                }
            }
        };
        vector<int> ans = {root->val};
        if (root->left == root->right) {
            return ans;
        }
        vector<int> left, right, leaves;
        dfs(left, root->left, 0);
        dfs(leaves, root, 1);
        dfs(right, root->right, 2);
        ans.insert(ans.end(), left.begin(), left.end());
        ans.insert(ans.end(), leaves.begin(), leaves.end());
        ans.insert(ans.end(), right.rbegin(), right.rend());
        return ans;
    }
};
/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[]}
 */
var boundaryOfBinaryTree = function (root) {
    const ans = [root.val];
    if (root.left === root.right) {
        return ans;
    }

    const left = [];
    const leaves = [];
    const right = [];

    const dfs = function (nums, root, i) {
        if (!root) {
            return;
        }
        if (i === 0) {
            if (root.left !== root.right) {
                nums.push(root.val);
                if (root.left) {
                    dfs(nums, root.left, i);
                } else {
                    dfs(nums, root.right, i);
                }
            }
        } else if (i === 1) {
            if (root.left === root.right) {
                nums.push(root.val);
            } else {
                dfs(nums, root.left, i);
                dfs(nums, root.right, i);
            }
        } else {
            if (root.left !== root.right) {
                nums.push(root.val);
                if (root.right) {
                    dfs(nums, root.right, i);
                } else {
                    dfs(nums, root.left, i);
                }
            }
        }
    };

    dfs(left, root.left, 0);
    dfs(leaves, root, 1);
    dfs(right, root.right, 2);
    return ans.concat(left).concat(leaves).concat(right.reverse());
};
/**
 * Definition for a binary tree node.
 * class TreeNode {
 *     val: number
 *     left: TreeNode | null
 *     right: TreeNode | null
 *     constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
 *         this.val = (val===undefined ? 0 : val)
 *         this.left = (left===undefined ? null : left)
 *         this.right = (right===undefined ? null : right)
 *     }
 * }
 */

function boundaryOfBinaryTree(root: TreeNode | null): number[] {
    const ans: number[] = [root.val];
    if (root.left === root.right) {
        return ans;
    }

    const left: number[] = [];
    const leaves: number[] = [];
    const right: number[] = [];

    const dfs = function (nums: number[], root: TreeNode | null, i: number) {
        if (!root) {
            return;
        }
        if (i === 0) {
            if (root.left !== root.right) {
                nums.push(root.val);
                if (root.left) {
                    dfs(nums, root.left, i);
                } else {
                    dfs(nums, root.right, i);
                }
            }
        } else if (i === 1) {
            if (root.left === root.right) {
                nums.push(root.val);
            } else {
                dfs(nums, root.left, i);
                dfs(nums, root.right, i);
            }
        } else {
            if (root.left !== root.right) {
                nums.push(root.val);
                if (root.right) {
                    dfs(nums, root.right, i);
                } else {
                    dfs(nums, root.left, i);
                }
            }
        }
    };

    dfs(left, root.left, 0);
    dfs(leaves, root, 1);
    dfs(right, root.right, 2);

    return ans.concat(left).concat(leaves).concat(right.reverse());
}
/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func boundaryOfBinaryTree(root *TreeNode) []int {
	ans := []int{root.Val}
	if root.Left == root.Right {
		return ans
	}

	left, leaves, right := []int{}, []int{}, []int{}

	var dfs func(nums *[]int, root *TreeNode, i int)
	dfs = func(nums *[]int, root *TreeNode, i int) {
		if root == nil {
			return
		}
		if i == 0 {
			if root.Left != root.Right {
				*nums = append(*nums, root.Val)
				if root.Left != nil {
					dfs(nums, root.Left, i)
				} else {
					dfs(nums, root.Right, i)
				}
			}
		} else if i == 1 {
			if root.Left == root.Right {
				*nums = append(*nums, root.Val)
			} else {
				dfs(nums, root.Left, i)
				dfs(nums, root.Right, i)
			}
		} else {
			if root.Left != root.Right {
				*nums = append(*nums, root.Val)
				if root.Right != nil {
					dfs(nums, root.Right, i)
				} else {
					dfs(nums, root.Left, i)
				}
			}
		}
	}

	dfs(&left, root.Left, 0)
	dfs(&leaves, root, 1)
	dfs(&right, root.Right, 2)

	ans = append(ans, left...)
	ans = append(ans, leaves...)
	for i := len(right) - 1; i >= 0; i-- {
		ans = append(ans, right[i])
	}

	return ans
}
Try this approach in the editor

Complexity analysis

ApproachTimeSpaceWhen to Use
DFS with Boundary ClassificationO(n)O(h)Best general solution. Processes the tree in one traversal while maintaining boundary state.
Separate Left Boundary, Leaves, Right Boundary TraversalsO(n)O(h)Good when clarity matters. Splits the boundary logic into simple steps.

Frequently asked questions

Is Boundary of Binary Tree easy or hard?

Boundary of Binary Tree is generally classified as a medium difficulty problem. The traversal itself is straightforward, but handling duplicates between left boundary, leaves, and right boundary requires careful logic.

Boundary of Binary Tree Python/Java solution

Most implementations use DFS recursion in Python, Java, C++, or Go. The code tracks whether a node belongs to the left boundary, right boundary, or leaf set and appends nodes to a result list in the correct order during traversal.

How to solve Boundary of Binary Tree in O(n)?

Traverse the tree using DFS and collect nodes in three categories: left boundary, leaves, and right boundary. Add left boundary nodes before recursion, collect leaves when both children are null, and append right boundary nodes after recursion so they appear in reverse order. Each node is processed once, giving O(n) complexity.

What is the best approach for Boundary of Binary Tree?

The most efficient approach uses depth-first search while classifying nodes as left boundary, right boundary, or leaf. Each node is visited once and placed in the result based on its boundary role. This produces the correct anti-clockwise order in O(n) time and O(h) space where h is the tree height.

Is Boundary of Binary Tree asked at Google/Amazon/Meta?

Boundary traversal problems appear in interviews at large tech companies because they test understanding of tree traversal and edge-case handling. Variants of this question have been reported in interviews at companies like Amazon and Google, especially for roles focused on data structures.

What data structure is used in Boundary of Binary Tree?

The primary data structure is a binary tree combined with depth-first search traversal. The solution typically stores the boundary nodes in an array or list while the recursion stack manages traversal state.

What is the time complexity of Boundary of Binary Tree?

The optimal solution runs in O(n) time because every node in the binary tree is visited exactly once during traversal. Space complexity is O(h) due to the recursion stack used in DFS, where h represents the height of the tree.

Comments

Now write it yourselfClose this page and solve Boundary of Binary Tree in the editor, without looking.
Practise Boundary of Binary Tree