List the Levels From the Bottom Up

Solve this Problem
Easy20–25 min
Topics
Companies

You 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:

Input:root = [17, 8, 25, 4, 12, null, 30, 2]
Output:[[2], [4, 12, 30], [8, 25], [17]]
Explanation:The levels top-down are [17], [8, 25], [4, 12, 30], [2]. The answer lists them in the opposite order: the deepest level (just node 2) first and the root last, while each level is still read left to right.

Test Case 2:

Input:root = [6, null, 9]
Output:[[9], [6]]
Explanation:Two levels, deepest first.

Test Case 3:

Input:root = []
Output:[]
Explanation:No levels.

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

Brute

Find 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).

TimeO(n · h)
SpaceO(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

Optimal

First 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.

TimeO(n)
SpaceO(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}

Related Problems