🧠
Iterative Postorder Traversal with Stack
💡 This approach replaces recursion with an explicit stack to avoid recursion overhead and stack overflow in very deep trees, which is important in production environments.
Intuition
Use an iterative postorder traversal to compute max gains bottom-up, simulating recursion with a stack and tracking visited nodes.
Algorithm
- Use a stack to traverse the tree in postorder iteratively.
- Track nodes and whether their children have been processed.
- For each node, compute max gains from left and right children once processed.
- Update global max path sum and store max gain for parent computations.
💡 This approach is harder to implement but avoids recursion limits and clarifies the traversal order.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def maxPathSum(root):
if not root:
return 0
max_sum = float('-inf')
stack = []
node = root
last_visited = None
gains = {}
while stack or node:
if node:
stack.append(node)
node = node.left
else:
peek = stack[-1]
if peek.right and last_visited != peek.right:
node = peek.right
else:
left_gain = max(gains.get(peek.left, 0), 0)
right_gain = max(gains.get(peek.right, 0), 0)
price_newpath = peek.val + left_gain + right_gain
max_sum = max(max_sum, price_newpath)
gains[peek] = peek.val + max(left_gain, right_gain)
last_visited = stack.pop()
node = None
return max_sum
# Driver code
if __name__ == '__main__':
root = TreeNode(-10)
root.left = TreeNode(9)
root.right = TreeNode(20, TreeNode(15), TreeNode(7))
print(maxPathSum(root)) # Output: 42
Line Notes
stack = []Initialize stack to simulate recursion
while stack or node:Loop until all nodes processed
if node:Go as left as possible
if peek.right and last_visited != peek.right:Process right child if not visited
left_gain = max(gains.get(peek.left, 0), 0)Get left child's max gain or 0 if none
right_gain = max(gains.get(peek.right, 0), 0)Get right child's max gain or 0 if none
max_sum = max(max_sum, price_newpath)Update global max path sum
gains[peek] = peek.val + max(left_gain, right_gain)Store max gain for parent use
import java.util.*;
class TreeNode {
int val;
TreeNode left, right;
TreeNode(int val) { this.val = val; }
}
public class Solution {
public int maxPathSum(TreeNode root) {
if (root == null) return 0;
int maxSum = Integer.MIN_VALUE;
Map<TreeNode, Integer> gains = new HashMap<>();
Deque<TreeNode> stack = new ArrayDeque<>();
TreeNode node = root, lastVisited = null;
while (!stack.isEmpty() || node != null) {
if (node != null) {
stack.push(node);
node = node.left;
} else {
TreeNode peek = stack.peek();
if (peek.right != null && lastVisited != peek.right) {
node = peek.right;
} else {
int leftGain = Math.max(gains.getOrDefault(peek.left, 0), 0);
int rightGain = Math.max(gains.getOrDefault(peek.right, 0), 0);
int priceNewPath = peek.val + leftGain + rightGain;
maxSum = Math.max(maxSum, priceNewPath);
gains.put(peek, peek.val + Math.max(leftGain, rightGain));
lastVisited = stack.pop();
node = null;
}
}
}
return maxSum;
}
public static void main(String[] args) {
TreeNode root = new TreeNode(-10);
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.maxPathSum(root)); // Output: 42
}
}
Line Notes
Map<TreeNode, Integer> gains = new HashMap<>();Store max gains for nodes to avoid recomputation
Deque<TreeNode> stack = new ArrayDeque<>();Stack to simulate recursion
while (!stack.isEmpty() || node != null) {Traverse until all nodes processed
if (peek.right != null && lastVisited != peek.right) {Process right child if not visited
int leftGain = Math.max(gains.getOrDefault(peek.left, 0), 0);Get left child's max gain or 0
int rightGain = Math.max(gains.getOrDefault(peek.right, 0), 0);Get right child's max gain or 0
maxSum = Math.max(maxSum, priceNewPath);Update global max path sum
gains.put(peek, peek.val + Math.max(leftGain, rightGain));Store max gain for parent use
#include <iostream>
#include <stack>
#include <unordered_map>
#include <algorithm>
#include <climits>
using namespace std;
struct TreeNode {
int val;
TreeNode *left, *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
class Solution {
public:
int maxPathSum(TreeNode* root) {
if (!root) return 0;
int maxSum = INT_MIN;
stack<TreeNode*> stk;
unordered_map<TreeNode*, int> gains;
TreeNode* node = root;
TreeNode* lastVisited = nullptr;
while (!stk.empty() || node) {
if (node) {
stk.push(node);
node = node->left;
} else {
TreeNode* peek = stk.top();
if (peek->right && lastVisited != peek->right) {
node = peek->right;
} else {
int leftGain = max(gains[peek->left], 0);
int rightGain = max(gains[peek->right], 0);
int priceNewPath = peek->val + leftGain + rightGain;
maxSum = max(maxSum, priceNewPath);
gains[peek] = peek->val + max(leftGain, rightGain);
lastVisited = peek;
stk.pop();
node = nullptr;
}
}
}
return maxSum;
}
};
int main() {
TreeNode* root = new TreeNode(-10);
root->left = new TreeNode(9);
root->right = new TreeNode(20);
root->right->left = new TreeNode(15);
root->right->right = new TreeNode(7);
Solution sol;
cout << sol.maxPathSum(root) << endl; // Output: 42
return 0;
}
Line Notes
stack<TreeNode*> stk;Stack to simulate recursion
unordered_map<TreeNode*, int> gains;Map to store max gains for nodes
while (!stk.empty() || node) {Traverse until all nodes processed
if (peek->right && lastVisited != peek->right) {Process right child if not visited
int leftGain = max(gains[peek->left], 0);Get left child's max gain or 0
int rightGain = max(gains[peek->right], 0);Get right child's max gain or 0
maxSum = max(maxSum, priceNewPath);Update global max path sum
gains[peek] = peek->val + max(leftGain, rightGain);Store max gain for parent use
class TreeNode {
constructor(val=0, left=null, right=null) {
this.val = val;
this.left = left;
this.right = right;
}
}
function maxPathSum(root) {
if (!root) return 0;
let maxSum = -Infinity;
const stack = [];
const gains = new Map();
let node = root;
let lastVisited = null;
while (stack.length > 0 || node !== null) {
if (node !== null) {
stack.push(node);
node = node.left;
} else {
const peek = stack[stack.length - 1];
if (peek.right !== null && lastVisited !== peek.right) {
node = peek.right;
} else {
const leftGain = Math.max(gains.get(peek.left) || 0, 0);
const rightGain = Math.max(gains.get(peek.right) || 0, 0);
const priceNewPath = peek.val + leftGain + rightGain;
maxSum = Math.max(maxSum, priceNewPath);
gains.set(peek, peek.val + Math.max(leftGain, rightGain));
lastVisited = stack.pop();
node = null;
}
}
}
return maxSum;
}
// Driver code
const root = new TreeNode(-10,
new TreeNode(9),
new TreeNode(20, new TreeNode(15), new TreeNode(7))
);
console.log(maxPathSum(root)); // Output: 42
Line Notes
const stack = [];Stack to simulate recursion
const gains = new Map();Map to store max gains for nodes
while (stack.length > 0 || node !== null) {Traverse until all nodes processed
if (peek.right !== null && lastVisited !== peek.right) {Process right child if not visited
const leftGain = Math.max(gains.get(peek.left) || 0, 0);Get left child's max gain or 0
const rightGain = Math.max(gains.get(peek.right) || 0, 0);Get right child's max gain or 0
maxSum = Math.max(maxSum, priceNewPath);Update global max path sum
gains.set(peek, peek.val + Math.max(leftGain, rightGain));Store max gain for parent use
Each node is visited once; stack and map use O(n) space in worst case for skewed trees.
💡 For large trees, this approach avoids recursion stack overflow but uses extra memory for the stack and map.
Interview Verdict: Accepted
This approach is practical for very deep trees where recursion might fail, though more complex to implement.