🧠
Optimal (DFS with Level Tracking and Post-Processing)
💡 This approach uses DFS to collect nodes by level, then reverses the collected levels at the end. It shows an alternative to BFS and helps understand tree traversal depth-first.
Intuition
Perform a DFS traversal, passing the current level as a parameter. Append node values to a list corresponding to their level. After traversal, reverse the list of levels to get bottom-up order.
Algorithm
- Initialize an empty list of lists to hold nodes per level.
- Define a recursive DFS function that takes a node and its level.
- If the current level list doesn't exist, create it.
- Append the node's value to its level list.
- Recursively call DFS on left and right children with level+1.
- After DFS completes, reverse the list of levels and return.
💡 The challenge is managing the level parameter and ensuring lists exist for each level before appending.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def levelOrderBottom(root):
levels = []
def dfs(node, level):
if not node:
return
if len(levels) == level:
levels.append([])
levels[level].append(node.val)
dfs(node.left, level + 1)
dfs(node.right, level + 1)
dfs(root, 0)
return levels[::-1]
# Example usage:
if __name__ == '__main__':
root = TreeNode(3)
root.left = TreeNode(9)
root.right = TreeNode(20, TreeNode(15), TreeNode(7))
print(levelOrderBottom(root))
Line Notes
levels = []Initialize list to hold nodes per level.
def dfs(node, level):Recursive DFS function with level tracking.
if len(levels) == level:Create new list for this level if it doesn't exist.
levels[level].append(node.val)Append current node's value to its level list.
return levels[::-1]Reverse levels to get bottom-up order.
import java.util.*;
class TreeNode {
int val;
TreeNode left, right;
TreeNode(int val) { this.val = val; }
}
public class Solution {
List<List<Integer>> levels = new ArrayList<>();
public List<List<Integer>> levelOrderBottom(TreeNode root) {
dfs(root, 0);
Collections.reverse(levels);
return levels;
}
private void dfs(TreeNode node, int level) {
if (node == null) return;
if (levels.size() == level) {
levels.add(new ArrayList<>());
}
levels.get(level).add(node.val);
dfs(node.left, level + 1);
dfs(node.right, level + 1);
}
// Example usage
public static void main(String[] args) {
TreeNode root = new TreeNode(3);
root.left = new TreeNode(9);
root.right = new TreeNode(20);
root.right.left = new TreeNode(15);
root.right.right = new TreeNode(7);
Solution sol = new Solution();
System.out.println(sol.levelOrderBottom(root));
}
}
Line Notes
List<List<Integer>> levels = new ArrayList<>();Store nodes grouped by level.
if (levels.size() == level) {Create new list for current level if needed.
levels.get(level).add(node.val);Add current node's value to its level list.
Collections.reverse(levels);Reverse levels to get bottom-up order.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct TreeNode {
int val;
TreeNode *left, *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
void dfs(TreeNode* node, int level, vector<vector<int>>& levels) {
if (!node) return;
if (levels.size() == level) {
levels.push_back(vector<int>());
}
levels[level].push_back(node->val);
dfs(node->left, level + 1, levels);
dfs(node->right, level + 1, levels);
}
vector<vector<int>> levelOrderBottom(TreeNode* root) {
vector<vector<int>> levels;
dfs(root, 0, levels);
reverse(levels.begin(), levels.end());
return levels;
}
int main() {
TreeNode* root = new TreeNode(3);
root->left = new TreeNode(9);
root->right = new TreeNode(20);
root->right->left = new TreeNode(15);
root->right->right = new TreeNode(7);
vector<vector<int>> res = levelOrderBottom(root);
for (auto &level : res) {
for (int val : level) cout << val << ' ';
cout << '\n';
}
return 0;
}
Line Notes
if (levels.size() == level) {Create new vector for current level if it doesn't exist.
levels[level].push_back(node->val);Add current node's value to its level vector.
dfs(node->left, level + 1, levels);Recurse left child with incremented level.
reverse(levels.begin(), levels.end());Reverse levels to get bottom-up order.
class TreeNode {
constructor(val=0, left=null, right=null) {
this.val = val;
this.left = left;
this.right = right;
}
}
function levelOrderBottom(root) {
const levels = [];
function dfs(node, level) {
if (!node) return;
if (levels.length === level) {
levels.push([]);
}
levels[level].push(node.val);
dfs(node.left, level + 1);
dfs(node.right, level + 1);
}
dfs(root, 0);
return levels.reverse();
}
// Example usage
const root = new TreeNode(3, new TreeNode(9), new TreeNode(20, new TreeNode(15), new TreeNode(7)));
console.log(levelOrderBottom(root));
Line Notes
const levels = [];Initialize array to hold nodes per level.
function dfs(node, level) {Recursive DFS with level tracking.
if (levels.length === level) {Create new array for current level if needed.
levels[level].push(node.val);Add current node's value to its level array.
return levels.reverse();Reverse levels to get bottom-up order.
DFS visits each node once, storing values by level. Reversing the levels is O(n).
💡 For n=10,000 nodes, this approach is as efficient as BFS but uses recursion which may affect stack space.
Interview Verdict: Accepted
This approach is a good alternative to BFS and shows mastery of DFS with level tracking.