0% completed
Problem Statement
Given the root
of a binary tree, collect a tree's leaf nodes
by following the given rules and return them in a 2D array.
Collect
all the leaf nodes from theleft to right
.Remove
all the leaf nodes.Repeat
until the tree is empty.
Examples
- Example 1:
- Input: root =
[1,2,3,4]
- Input: root =
-
Expected Output:
[[4,3],[2],[1]]
-
Justification: Initially, nodes 4 and 3 are leaves and are removed in the first round. In the second round, node 2 becomes a leaf. Node 1 is the last one remaining and is removed in the final round.
-
Example 2:
- Input: root =
[1,2,3,null, null,4,5,null, null,6,null]
- Input: root =
-
Expected Output:
[[2,4,6],[5],[3],[1]]
-
Justification: In the first round, the leaves are nodes 2, 4, and 6. Once removed, node 5 becomes the leaf in the second round, and then node
3
becomes the leaf node in the third round. Finally, node 1 is left and removed in the last round. -
Example 3:
- Input: root =
[1,2,null,3,null,4]
- Input: root =
- Expected Output:
[[4],[3],[2],[1]]
- Justification: This tree has a linear structure. Each node becomes a leaf one after the other, starting from node 4 to node 1.
Solution
To solve this problem, we employ a depth-first search (DFS) strategy to identify the leaves of the binary tree at each level. The key idea is to traverse the tree from the bottom up. This approach allows us to determine the "height" of each node, with the height of a leaf being 0. The height of a node is the number of edges on the longest downward path between that node and a leaf. By calculating these heights during our DFS traversal, we can group nodes with the same height together, as they will be removed in the same round.
This method is effective because it leverages the natural structure of a binary tree to minimize the amount of work needed to identify leaves at each round. By using the height of nodes as a guide, we avoid the need to repeatedly traverse the entire tree to find leaves. Additionally, this approach ensures that our solution is scalable and can handle trees of various sizes and shapes efficiently.
Step-by-Step Algorithm
-
Implement the DFS Function:
- Define a recursive function
dfs
that takes a TreeNode and returns its height. The height of a null node is considered -1. This function performs several key operations:- It first checks if the current node is null. If so, it returns -1.
- It recursively calls itself for the left and right children of the current node to calculate their heights.
- It calculates the current node's height as the maximum of its children's heights plus one.
- It adds the current node's value to the appropriate sublist in the list of leaves, based on the current node's height. If the sublist for the current height doesn't exist, it creates a new sublist.
- It returns the current node's height.
- Define a recursive function
-
Find Leaves of the Binary Tree:
- Define the main function
findLeaves
that takes the root of the binary tree. This function initializes the list of leaves and calls thedfs
function with the root node. - The
dfs
function populates the list with leaves grouped by their removal rounds as it traverses the tree. - Finally, the
findLeaves
function returns the list of leaves.
- Define the main function
Algorithm Walkthrough
Let's consider the Input: root = [1,2,3,null,null,4,5,null,null,6,null]
1
/ \
2 3
/ \
4 5
/
6
-
Start DFS with Root Node
1
:- The root node
1
is not a leaf. We proceed with its children.
- The root node
-
Traverse to the Left Child
2
of Root Node1
:- Node
2
is a leaf node (no children). - It's added to
leaves[0]
since its height from the bottom is0
. - The list now looks like
[[2]]
.
- Node
-
Backtrack to Node
1
and Traverse to the Right Child3
:- Node
3
is not a leaf. We proceed with its children.
- Node
-
Traverse to the Left Child
4
of Node3
:- Node
4
is a leaf node. - It's added to
leaves[0]
, updating the list to[[2, 4]]
.
- Node
-
Traverse to the Right Child
5
of Node3
:- Node
5
is not a leaf. We proceed with its child.
- Node
-
Traverse to the Left Child
6
of Node5
:- Node
6
is a leaf node. - It's added to
leaves[0]
, updating the list to[[2, 4, 6]]
.
- Node
-
Backtrack to Node
5
After Removing6
:- Now, Node
5
becomes a leaf. - It's height from the bottom is
1
(since it was one level above6
). - It's added to
leaves[1]
, updating the list to[[2, 4, 6], [5]]
.
- Now, Node
-
Backtrack to Node
3
After Removing Its Children (4
and5
):- Node
3
now becomes a leaf. - Its height from the bottom is
2
. - It's added to
leaves[2]
, updating the list to[[2, 4, 6], [5], [3]]
.
- Node
-
Backtrack to Root Node
1
After Removing Its Children:- Finally, the root node
1
becomes the last leaf to be removed. - Its height from the bottom is
3
. - It's added to
leaves[3]
, completing the list as[[2, 4, 6], [5], [3], [1]]
.
- Finally, the root node
Code
Complexity Analysis
Time Complexity
- DFS Traversal: The Depth-First Search (DFS) algorithm visits each node exactly once. Therefore, the time complexity is O(N), where (N) is the number of nodes in the binary tree.
Space Complexity
- Recursive Stack: The DFS algorithm uses a recursive stack. In the worst case (a skewed tree), the height of the recursion tree can be O(N), leading to a space complexity of O(N).
- Output List: The space taken by the output list is O(N) since every node is stored in the list exactly once.
- Combined: Considering both the recursive stack and the output list, the overall space complexity remains O(N).
Table of Contents
Problem Statement
Examples
Solution
Step-by-Step Algorithm
Algorithm Walkthrough
Code
Complexity Analysis
Time Complexity
Space Complexity