Sale: Get 60% Off on all Pro Plans. Buy Now

Find Leaves of Binary Tree

Medium DFS

Problem

Given the root of a binary tree, return a list of lists where each sublist contains the values of the nodes that are removed as leaves in each iteration until the tree is empty.

  • The number of nodes in the tree is in the range [1, 1000]
  • −1000 ≤ Node.val ≤ 1000

Example

Input: root = [1,2,3,4,5]
Output: [[4,5,3],[2],[1]]

The algorithm works by assigning a height to each node, defined as the number of edges on the longest path from the node down to a leaf. Leaves have height 0. For the example tree: 1. Nodes 4, 5, and 3 are leaves with height 0, so they form the first list. 2. Node 2 has children 4 and 5, so its height is 1, forming the second list. 3. Node 1 has children 2 and 3, so its height is 2, forming the last list. This height-based grouping corresponds exactly to the order in which nodes would be removed if leaves were iteratively pruned.

Approach

Straightforward Solution

A naive approach would simulate the iterative removal of leaves by repeatedly traversing the tree to find leaves and remove them, which is inefficient and can lead to O(n²) time complexity.

Core Observation

The height of a node in a binary tree can be defined recursively as 1 plus the maximum height of its children, with leaves having height 0. Grouping nodes by their height naturally partitions them into layers corresponding to the order in which they would be removed as leaves.

Path to Optimal

Preview

Instead of simulating leaf removal, the problem can be reframed as computing the height of each node via a post-order DFS traversal. This approach assigns each node a height that corresponds to the iteration it would be removed…

Full step-by-step walkthrough on Pro

Optimal Approach

Preview

Perform a DFS that returns the height of each node. For each node, compute the height of its left and right children, take the maximum, add one, and append the node's value to the list corresponding to that height…

Full step-by-step walkthrough on Pro

Want the full reasoning chain?

Unlock the complete walkthrough, line-by-line analysis, and recall drill.

Unlock Pro

Time

O(n)

Each node is visited exactly once during the DFS traversal, and all operations per node are O(1), resulting in linear time relative to the number of nodes.

Space

O(n)

The recursion stack can grow up to O(h) where h is the height of the tree, which is O(n) in the worst case. Additionally, the output list stores all node values, which is O(n) space.

Pattern Spotlight

DFS (Post-Order Traversal with State Aggregation)

When a problem requires grouping nodes by a property dependent on their descendants, a post-order DFS that computes and returns that property bottom-up enables efficient aggregation without explicit simulation.

Solution

Python
1class Solution:
2 def findLeaves(self, root: Optional[TreeNode]) -> List[List[int]]:
3 res = []
4
5 def dfs(node):
6 if not node:
7 return -1
8
9 left = dfs(node.left)
10 right = dfs(node.right)
11
12 height = 1 + max(left, right)
13
14 if height == len(res):
15 res.append([])
16
17 res[height].append(node.val)
18
19 return height
20
21 dfs(root)
22 return res

Step-by-Step Solution

1

Compute Node Heights via Post-Order DFS and Group Nodes

3res = []
5def dfs(node):
6 if not node:
7 return -1
9 left = dfs(node.left)
10 right = dfs(node.right)
12 height = 1 + max(left, right)
14 if height == len(res):
15 res.append([])
17 res[height].append(node.val)
19 return height
21dfs(root)
22return res

Objective

To recursively compute the height of each node and group nodes by their height in the result list.

Key Insight

By performing a post-order DFS, the algorithm ensures that the heights of the children are computed before the parent. The height of a node is 1 plus the maximum height of its children, which naturally corresponds to the iteration at which the node would be removed as a leaf. Grouping nodes by height during traversal avoids simulating leaf removal and achieves the solution in a single pass.

Interview Quick-Check

Core Logic

The DFS returns the height of each node, defined as 1 + max(left child's height, right child's height), enabling grouping nodes by their removal iteration.

State & Boundaries

The base case returns -1 for null nodes, so leaves have height 0, ensuring correct height calculation.

Common Pitfalls & Bugs

Forgetting to append a new list when the current height equals the length of the result list leads to index errors or missing groups.

Complexity

This approach visits each node once, resulting in O(n) time and O(n) space complexity.

Line Analysis

This solution has 2 Critical lines interviewers watch for.

Line 3 Critical
res = []

Initialize the result list to store groups of leaves by height.

This list accumulates nodes grouped by their computed height, which corresponds to the iteration they would be removed as leaves.

Line 5 Critical
def dfs(node):

Define the DFS helper function to compute node heights.

Encapsulating the height computation in a recursive function enables a clean post-order traversal that aggregates state bottom-up.

Full line-by-line criticality + rationale for all 13 lines available on Pro.

Test Your Understanding

Why does grouping nodes by their height computed via DFS correspond to the order in which leaves are removed iteratively?

See the answer with Pro.

Related Problems

DFS pattern

Don't just read it. Drill it.

Reconstruct Find Leaves of Binary Tree from memory until it sticks. AlgoDrill blanks out key lines and makes you fill them back in, step by step.

Unlock the Find Leaves of Binary Tree drill

or drill a free problem