# 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 findLeaves(self, root):
res = []
def dfs(node):
if not node:
return -1
left = dfs(node.left)
right = dfs(node.right)
level = max(left, right) + 1
if level == len(res):
res.append([])
res[level].append(node.val)
return level
dfs(root)
return res
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<vector<int>> findLeaves(TreeNode* root) {
vector<vector<int>> res;
function<int(TreeNode*)> dfs = [&](TreeNode* node) {
if (!node) return -1;
int left = dfs(node->left);
int right = dfs(node->right);
int level = max(left, right) + 1;
if (level == res.size())
res.push_back({});
res[level].push_back(node->val);
return level;
};
dfs(root);
return res;
}
};
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<List<Integer>> findLeaves(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
dfs(root, res);
return res;
}
private int dfs(TreeNode node, List<List<Integer>> res) {
if (node == null) return -1;
int left = dfs(node.left, res);
int right = dfs(node.right, res);
int level = Math.max(left, right) + 1;
if (level == res.size())
res.add(new ArrayList<>());
res.get(level).add(node.val);
return level;
}
}
/**
* 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 findLeaves = function(root) {
const res = [];
function dfs(node) {
if (!node) return -1;
let left = dfs(node.left);
let right = dfs(node.right);
let level = Math.max(left, right) + 1;
if (level === res.length) res.push([]);
res[level].push(node.val);
return level;
}
dfs(root);
return res;
};
Given the root of a binary tree, repeatedly remove all of its leaves, and collect the leaves removed at each step until the tree is empty. Return a list of lists, where each inner list contains the values of the leaves removed at that step.
TreeNode
objects with val
, left
, and right
attributes.At first glance, the problem seems to require simulating the process of removing leaves from a binary tree, layer by layer. A brute-force approach would be to physically remove all leaves in each iteration, traverse the tree to find the leaves, and repeat until the tree is empty. However, this would be inefficient, as it would require multiple traversals and modifications of the tree.
Instead, we can notice that each node is "removed" as a leaf at a certain step, which depends on its distance from the farthest leaf. Specifically, a node becomes a leaf after all of its children have been removed. This leads to the insight that we can assign a "level" to each node: leaves are level 0, their parents are level 1, and so on.
By performing a post-order traversal, we can compute the level for each node in a single pass, grouping nodes by their level to simulate the rounds of leaf removal.
max(left child level, right child level) + 1
.This approach does not modify the tree and collects all results in a single traversal, making it efficient and elegant.
Consider the following binary tree:
1 / \ 2 3 / \ 4 5
Let's trace the process:
The final output is [[4, 5, 3], [2], [1]]
.
Using the algorithm, each node is assigned a level: 4, 5, and 3 get level 0; 2 gets level 1; 1 gets level 2. Grouping by level gives the correct answer.
By rethinking the problem as grouping nodes by the step at which they become leaves, we avoid repeatedly modifying the tree and instead use a single post-order traversal to assign levels to nodes. This results in an efficient O(n) time and space solution that is easy to implement and understand. The key insight is that each node's "removal round" is determined by its maximum distance from a leaf, enabling us to build the answer in one pass.