Quick Overview

Given a binary tree stored as child-index arrays, return its boundary values anticlockwise: the root, the left boundary, the leaves from left to right and the right boundary from bottom to top, whose total is the boundary sum. It tests precise traversal rules and edge cases.

Collect a Binary Tree's Outer Boundary Values Anticlockwise

Company: Snowflake

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: medium

Interview Round: Technical Screen

The question asks for the boundary of a binary tree and its sum. Return the boundary values in boundary order, read anticlockwise from the root; the boundary sum is the total of the returned list. ### Function Signature ```python def tree_boundary(values: list[int], left: list[int], right: list[int]) -> list[int]: ``` ### Rules - The tree has `n` nodes numbered `0` to `n - 1`, and node `0` is the root. `values[i]` is the value of node `i`, and `left[i]` and `right[i]` are the indices of its left and right children, or `-1` when that child is missing. - A leaf is a node with no children. The root is never treated as a leaf, even when it has no children. - The left boundary starts at the root's left child. From there, repeatedly move to the current node's left child if it exists, otherwise to its right child, and stop at the first leaf. The left boundary is the nodes visited, excluding that final leaf. If the root has no left child, the left boundary is empty. - The right boundary is the mirror image: start at the root's right child, repeatedly move to the right child if it exists, otherwise to the left child, stop at the first leaf and exclude it. If the root has no right child, the right boundary is empty. - The leaves are all the leaves of the tree, in the order a left-to-right depth-first traversal reaches them. - Return the root's value, then the left boundary's values from top to bottom, then the leaves' values, then the right boundary's values from bottom to top. ### Constraints - `1 <= n <= 10^4`, and `len(values) == len(left) == len(right) == n` - `-1000 <= values[i] <= 1000` - Every child index is `-1` or between `1` and `n - 1`, every node other than `0` is the child of exactly one node, and the links form a single binary tree rooted at node `0`. - The tree can be a single path, so its depth can reach `n`. ### Examples **Example 1** ```text 1 \ 2 / \ 3 4 ``` ```text Input: values = [1, 2, 3, 4], left = [-1, 2, -1, -1], right = [1, 3, -1, -1] Output: [1, 3, 4, 2] ``` The root has no left child, so the left boundary is empty. The leaves are 3 and 4. The right boundary is the node with value 2; the leaf 4 that ends it is listed with the leaves. The boundary sum is 10. **Example 2** ```text 1 / \ 2 3 / \ / 4 5 6 / \ / \ 7 8 9 10 ``` ```text Input: values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], left = [1, 3, 5, -1, 6, 8, -1, -1, -1, -1], right = [2, 4, -1, -1, 7, 9, -1, -1, -1, -1] Output: [1, 2, 4, 7, 8, 9, 10, 6, 3] ``` Node `i` holds the value `i + 1`. The left boundary is 2, whose next step reaches the leaf 4. The leaves are 4, 7, 8, 9 and 10. The right boundary from the top is 3, then 6, because 3 has no right child, and it stops at the leaf 10; read from the bottom it is 6, 3. The boundary sum is 50. **Example 3** ```text Input: values = [5], left = [-1], right = [-1] Output: [5] ``` A lone root is not a leaf, so it appears once.

Overview: Given a binary tree stored as child-index arrays, return its boundary values anticlockwise: the root, the left boundary, the leaves from left to right and the right boundary from bottom to top, whose total is the boundary sum. It tests precise traversal rules and edge cases.

A binary tree is stored as three parallel arrays. Return the values on its boundary, read anticlockwise starting from the root. The tree's boundary sum is the total of the returned list; the function returns only the list. The tree has `n` nodes numbered `0` to `n - 1`, and node `0` is the root. `values[i]` is the value of node `i`, and `left[i]` and `right[i]` are the indices of its left and right children, or `-1` when that child is missing. - A **leaf** is a node with no children. The root is never treated as a leaf, even when it has no children, so a lone root appears exactly once in the answer. - The **left boundary** starts at the root's left child. From there, repeatedly move to the current node's left child if it exists, otherwise to its right child, and stop at the first leaf. The left boundary is the nodes visited, excluding that final leaf. If the root has no left child, the left boundary is empty. - The **right boundary** is the mirror image: start at the root's right child, repeatedly move to the right child if it exists, otherwise to the left child, stop at the first leaf and exclude it. If the root has no right child, the right boundary is empty. - The **leaves** are all the leaves of the tree, in the order a left-to-right depth-first traversal reaches them. Return a list containing the root's value, then the left boundary's values from top to bottom, then the leaves' values, then the right boundary's values from bottom to top. No returned value can exceed 2^31 - 1 in magnitude: every value is between -1000 and 1000, so 32-bit integers suffice in every language. ### Constraints - `1 <= n <= 10^4`, and `len(values) == len(left) == len(right) == n` - `-1000 <= values[i] <= 1000` - Every child index is `-1` or between `1` and `n - 1`, every node other than `0` is the child of exactly one node, and the links form a single binary tree rooted at node `0`. - The tree can be a single path, so its depth can reach `n`. ### Example 1 ```text 1 \ 2 / \ 3 4 ``` ```text Input: values = [1, 2, 3, 4], left = [-1, 2, -1, -1], right = [1, 3, -1, -1] Output: [1, 3, 4, 2] ``` The root has no left child, so the left boundary is empty. The leaves are 3 and 4. The right boundary is the node with value 2; the leaf 4 that ends it is listed with the leaves. The boundary sum is 10. ### Example 2 ```text Input: values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], left = [1, 3, 5, -1, 6, 8, -1, -1, -1, -1], right = [2, 4, -1, -1, 7, 9, -1, -1, -1, -1] Output: [1, 2, 4, 7, 8, 9, 10, 6, 3] ``` Node `i` holds the value `i + 1`. The left boundary is 2, whose next step reaches the leaf 4. The leaves are 4, 7, 8, 9 and 10. The right boundary from the top is 3, then 6 (3 has no right child, so the walk moves to its left child), and it stops at the leaf 10; read from the bottom it is 6, 3. The boundary sum is 50.

Constraints

  • 1 <= n <= 10^4, and len(values) == len(left) == len(right) == n
  • -1000 <= values[i] <= 1000
  • Every child index is -1 or between 1 and n - 1, every node other than 0 is the child of exactly one node, and the links form a single binary tree rooted at node 0.
  • The tree can be a single path, so its depth can reach n.

Examples

Input: ([1, 2, 3, 4], [-1, 2, -1, -1], [1, 3, -1, -1])

Expected Output: [1, 3, 4, 2]

Explanation: Source Example 1: no left child so the left boundary is empty; the right boundary is 2 and its terminating leaf 4 appears only among the leaves.

Input: ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 3, 5, -1, 6, 8, -1, -1, -1, -1], [2, 4, -1, -1, 7, 9, -1, -1, -1, -1])

Expected Output: [1, 2, 4, 7, 8, 9, 10, 6, 3]

Explanation: Source Example 2: the right boundary steps from 3 to its left child 6 because 3 has no right child, and is read bottom to top as 6, 3.

Hints

  1. Treat the answer as four separate pieces (the root, the left boundary, the leaves and the right boundary) and check that no node can land in two of them.
  2. At every step a boundary walk has exactly one node to move to, and the leaf where it ends belongs to the leaf list rather than to the boundary.
  3. A single path can be 10^4 nodes deep, so make sure your traversal does not depend on a deep call stack.

Loading coding console...

Show the approach

Approach

Build the answer from four disjoint pieces and concatenate them. (1) The root's value. (2) Left boundary: start at left[0]; while the current node exists and has at least one child, record its value and step to its left child if present, otherwise to its right child. The loop stops on the first leaf without recording it. (3) Leaves: an iterative preorder traversal with an explicit stack (push the right child before the left so the left subtree is finished first) records every node other than the root that has no children; preorder with left before right is exactly the left-to-right depth-first order the statement asks for. (4) Right boundary: the mirrored walk from right[0] (prefer the right child, else the left), collected top to bottom and then reversed. Correctness: a non-leaf always has at least one child, so each boundary walk has exactly one next node and ends on a leaf, which it never records; every leaf therefore appears exactly once, in the leaf list. The left boundary lies inside the root's left subtree and the right boundary inside its right subtree, so the pieces never overlap, and the root, which is never a leaf, appears only once. Edge cases: a lone root returns just its own value; a missing left or right child of the root gives an empty boundary on that side; a root child that is itself a leaf appears only among the leaves. Loops and an explicit stack replace recursion, so a single path of 10^4 nodes cannot overflow the call stack.

Time complexity:
O(n)
Space complexity:
O(n)