List the Levels From the Bottom Up
Solve this ProblemYou are given the root of a binary tree. Group the node values by level and return the groups starting from the deepest level and ending with the root's level; inside each group, keep the values in left-to-right order. For an empty tree return an empty list.
You can walk the tree repeatedly, once per level from the bottom, or collect the levels top-down with a queue in one pass and simply reverse the order of the rows.
Test Case 1:
Test Case 2:
Test Case 3:
Constraints
- ◆
0 ≤ number of nodes ≤ 100 - ◆
−100 ≤ node.val ≤ 100 - ◆
The tree is given as its root node (null for an empty tree); each node has a val, a left child and a right child - ◆
Return one list per level, but starting with the DEEPEST level and ending with the root level. Inside each level, list the values from left to right. An empty tree gives an empty list
Try the Dry Run
Don't just read the solution — watch it execute, one step at a time.
Approach & Solutions
Brute Force — Walk the Tree Once per Level, Deepest First
BruteFind the height h of the tree, then produce the levels from depth h − 1 down to 0. For each depth, walk the whole tree again with a helper that counts down the remaining levels to descend (left child first, then right child); the nodes it finds at count 0 are that level's values, already in left-to-right order. Since the depths are visited from the bottom, the rows come out deepest-first with no reversing. But each of the h passes re-walks up to n nodes: O(n · h) time (O(n²) for a tall thin tree).
O(n · h)O(n)1class Solution {
2 public List<List<Integer>> bottomUpLevels(TreeNode root) {
3 List<List<Integer>> levels = new ArrayList<>();
4 int h = height(root);
5 for (int depth = h - 1; depth >= 0; depth--) {
6 List<Integer> row = new ArrayList<>();
7 collect(root, depth, row);
8 levels.add(row);
9 }
10 return levels;
11 }
12
13 private int height(TreeNode node) {
14 if (node == null) return 0;
15 return 1 + Math.max(height(node.left), height(node.right));
16 }
17
18 private void collect(TreeNode node, int depth, List<Integer> row) {
19 if (node == null) return;
20 if (depth == 0) {
21 row.add(node.val);
22 return;
23 }
24 collect(node.left, depth - 1, row);
25 collect(node.right, depth - 1, row);
26 }
27}Optimal — Queue by Levels, Then Reverse the Rows
OptimalFirst do the ordinary top-down level traversal with a queue: at each round the queue size is the number of nodes on the level, so take that many nodes, record their values in a row, and queue their children. Append each finished row to the answer. The rows are then in root-first order, so reversing the list of rows (a level count of at most h — cheap) yields the deepest-first order. Each node is queued and taken once: O(n) time; the answer itself needs O(n) space, and the queue holds at most one or two levels.
O(n)O(n)1class Solution {
2 public List<List<Integer>> bottomUpLevels(TreeNode root) {
3 List<List<Integer>> levels = new ArrayList<>();
4 if (root == null) return levels;
5 Queue<TreeNode> queue = new ArrayDeque<>();
6 queue.add(root);
7 while (!queue.isEmpty()) {
8 int size = queue.size();
9 List<Integer> row = new ArrayList<>();
10 for (int i = 0; i < size; i++) {
11 TreeNode node = queue.poll();
12 row.add(node.val);
13 if (node.left != null) queue.add(node.left);
14 if (node.right != null) queue.add(node.right);
15 }
16 levels.add(row);
17 }
18 Collections.reverse(levels);
19 return levels;
20 }
21}