Find Largest Value in Each Tree Row
Medium · Graphs · Explanation and code example
Iterative DFS
How it works
The recursive DFS can be converted to an iterative approach using a stack. Each stack entry stores both the node and its level. This avoids recursion overhead while maintaining the same logic.
Steps
- If the root is
null, return an empty list. - Initialize a stack with
(root, 0)and an empty result list. - While the stack is not empty:
- Pop
(node, level)from the stack. - If
levelequals the result list size, append the node's value. - Otherwise, update
res[level]to the maximum of its current value and the node's value. - Push the right child first (if exists), then the left child, both with
level + 1.
- Pop
- Return the result list.
Complexity
- Time complexity:
O(n) - Space complexity:
O(n)
Things to watch for
Not Handling Empty Tree
Forgetting to check if the root is null before processing leads to null pointer exceptions or runtime errors. Always add an early return for the empty tree case, returning an empty list rather than attempting to traverse a non-existent tree.
Initializing Row Maximum Incorrectly
When tracking the maximum value for each row, initializing rowMax to 0 or a small positive number fails for trees with negative values. The correct approach is to initialize rowMax with the first node's value in that row, or use Integer.MIN_VALUE (or equivalent) to ensure negative values are handled correctly.
Mixing Up Level Boundaries in BFS
In BFS, you must process all nodes at the current level before moving to the next. A common mistake is not capturing the queue size before the inner loop, causing nodes from the next level to be processed prematurely. Always store queue.size() at the start of each level iteration and use that fixed count for the inner loop.
Python code example
from typing import List, Optional
# 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 largestValues(self, root: Optional[TreeNode]) -> List[int]:
if not root:
return []
res = []
stack = [(root, 0)]
while stack:
node, level = stack.pop()
if level == len(res):
res.append(node.val)
else:
res[level] = max(res[level], node.val)
if node.right:
stack.append((node.right, level + 1))
if node.left:
stack.append((node.left, level + 1))
return res
C++ code example
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> largestValues(TreeNode* root) {
if (!root) return {};
vector<int> res;
stack<pair<TreeNode*, int>> stk;
stk.push({root, 0});
while (!stk.empty()) {
auto [node, level] = stk.top();stk.pop();
if (level == res.size()) {
res.push_back(node->val);
} else {
res[level] = max(res[level], node->val);
}
if (node->right) stk.push({node->right, level + 1});
if (node->left) stk.push({node->left, level + 1});
}
return res;
}
};
Source and license
Adapted from NeetCode’s source · MIT license. Node types are supplied by LeetCode where needed.