🧠
Brute Force (DFS with Level Tracking)
💡 This approach uses a simple depth-first search to explore all nodes, tracking the level to update the maximum value per level. It is intuitive but less efficient than BFS for this problem.
Intuition
Traverse the tree recursively, passing the current level. For each node, update the maximum value found so far at that level.
Algorithm
- Initialize an empty list to store max values per level.
- Define a recursive DFS function that takes a node and its level.
- If the current level is not yet in the list, append the node's value.
- Otherwise, update the max value for that level if current node's value is larger.
- Recursively call DFS on left and right children with level + 1.
- Return the list of max values after traversal.
💡 The recursion and level tracking can be tricky to visualize at first, but it ensures every node is visited exactly once.
from typing import Optional, List
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def largestValues(root: Optional[TreeNode]) -> List[int]:
res = []
def dfs(node, level):
if not node:
return
if level == len(res):
res.append(node.val)
else:
res[level] = max(res[level], node.val)
dfs(node.left, level + 1)
dfs(node.right, level + 1)
dfs(root, 0)
return res
# Example usage:
# Construct tree: [1,3,2,5,3,null,9]
root = TreeNode(1,
TreeNode(3, TreeNode(5), TreeNode(3)),
TreeNode(2, None, TreeNode(9)))
print(largestValues(root)) # Output: [1, 3, 9]
Line Notes
def dfs(node, level):Defines recursive helper to traverse nodes with current level info
if not node:Base case to stop recursion at leaf's child
if level == len(res):First time visiting this level, so append current node's value
res[level] = max(res[level], node.val)Update max value for this level if current node's value is larger
import java.util.*;
class TreeNode {
int val;
TreeNode left, right;
TreeNode(int val) { this.val = val; }
}
public class Solution {
public List<Integer> largestValues(TreeNode root) {
List<Integer> res = new ArrayList<>();
dfs(root, 0, res);
return res;
}
private void dfs(TreeNode node, int level, List<Integer> res) {
if (node == null) return;
if (level == res.size()) {
res.add(node.val);
} else {
res.set(level, Math.max(res.get(level), node.val));
}
dfs(node.left, level + 1, res);
dfs(node.right, level + 1, res);
}
// Example usage
public static void main(String[] args) {
TreeNode root = new TreeNode(1);
root.left = new TreeNode(3);
root.right = new TreeNode(2);
root.left.left = new TreeNode(5);
root.left.right = new TreeNode(3);
root.right.right = new TreeNode(9);
Solution sol = new Solution();
System.out.println(sol.largestValues(root)); // Output: [1, 3, 9]
}
}
Line Notes
private void dfs(TreeNode node, int level, List<Integer> res)Recursive DFS helper with level and result list
if (node == null) return;Stops recursion at null nodes
if (level == res.size()) {First time visiting this level, add node's value
res.set(level, Math.max(res.get(level), node.val));Update max value for this level if current node's value is larger
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
void dfs(TreeNode* node, int level, vector<int>& res) {
if (!node) return;
if (level == (int)res.size()) {
res.push_back(node->val);
} else {
res[level] = max(res[level], node->val);
}
dfs(node->left, level + 1, res);
dfs(node->right, level + 1, res);
}
vector<int> largestValues(TreeNode* root) {
vector<int> res;
dfs(root, 0, res);
return res;
}
int main() {
TreeNode* root = new TreeNode(1);
root->left = new TreeNode(3);
root->right = new TreeNode(2);
root->left->left = new TreeNode(5);
root->left->right = new TreeNode(3);
root->right->right = new TreeNode(9);
vector<int> result = largestValues(root);
for (int val : result) cout << val << " ";
cout << endl; // Output: 1 3 9
return 0;
}
Line Notes
void dfs(TreeNode* node, int level, vector<int>& res)DFS helper with level and reference to result vector
if (!node) return;Base case to stop recursion at null nodes
if (level == (int)res.size()) {First time visiting this level, push current node's value
res[level] = max(res[level], node->val);Update max value for this level if current node's value is larger
class TreeNode {
constructor(val=0, left=null, right=null) {
this.val = val;
this.left = left;
this.right = right;
}
}
function largestValues(root) {
const res = [];
function dfs(node, level) {
if (!node) return;
if (level === res.length) {
res.push(node.val);
} else {
res[level] = Math.max(res[level], node.val);
}
dfs(node.left, level + 1);
dfs(node.right, level + 1);
}
dfs(root, 0);
return res;
}
// Example usage:
const root = new TreeNode(1,
new TreeNode(3, new TreeNode(5), new TreeNode(3)),
new TreeNode(2, null, new TreeNode(9))
);
console.log(largestValues(root)); // Output: [1, 3, 9]
Line Notes
function dfs(node, level) {Recursive DFS helper with current node and level
if (!node) return;Stops recursion when node is null
if (level === res.length) {First time visiting this level, add node's value
res[level] = Math.max(res[level], node.val);Update max value for this level if current node's value is larger
Each node is visited once, so time is O(n). Space is O(h) due to recursion stack, where h is tree height.
💡 For a tree with 20 nodes, this means about 20 operations and stack depth up to 20 in worst case.
Interview Verdict: Accepted
This approach is accepted but recursion stack can be large for skewed trees; still good for understanding.